├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── client ├── php │ └── client.php └── python │ ├── bench.py │ └── client.py ├── config ├── main.ini └── workflow.xml ├── engine ├── Context.h ├── Plugin.h ├── PluginHelper.cpp ├── PluginHelper.h ├── Work.cpp ├── Work.h ├── Workflow.cpp └── Workflow.h ├── json ├── Json.cpp ├── Json.h ├── Parser.cpp └── Parser.h ├── kill.sh ├── main.cpp ├── plugin ├── EchoPlugin.cpp ├── EchoPlugin.h ├── TestPlugin.cpp ├── TestPlugin.h ├── UserPlugin.cpp └── UserPlugin.h ├── server ├── Server.cpp └── Server.h ├── socket ├── ClientSocket.cpp ├── ClientSocket.h ├── EventPoller.cpp ├── EventPoller.h ├── ServerSocket.cpp ├── ServerSocket.h ├── Socket.cpp ├── Socket.h ├── SocketHandler.cpp └── SocketHandler.h ├── task ├── EchoTask.cpp ├── EchoTask.h ├── PingTask.cpp ├── PingTask.h ├── TaskFactory.h ├── WorkTask.cpp └── WorkTask.h ├── thread ├── AutoLock.cpp ├── AutoLock.h ├── Condition.cpp ├── Condition.h ├── Mutex.cpp ├── Mutex.h ├── Task.cpp ├── Task.h ├── TaskDispatcher.cpp ├── TaskDispatcher.h ├── Thread.cpp ├── Thread.h ├── ThreadPool.cpp ├── ThreadPool.h ├── WorkerThread.cpp └── WorkerThread.h ├── utility ├── IniFile.cpp ├── IniFile.h ├── Logger.cpp ├── Logger.h ├── ObjectPool.h ├── Singleton.h ├── System.cpp └── System.h └── xml ├── Document.cpp ├── Document.h ├── Element.cpp └── Element.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Log 5 | *.log 6 | 7 | # pyenv 8 | .idea/ 9 | 10 | # vscode 11 | .vscode 12 | 13 | # Compiled Object files 14 | *.slo 15 | *.lo 16 | *.o 17 | *.obj 18 | 19 | # Precompiled Headers 20 | *.gch 21 | *.pch 22 | 23 | # Compiled Dynamic libraries 24 | *.so 25 | *.dylib 26 | *.dll 27 | 28 | # Fortran module files 29 | *.mod 30 | *.smod 31 | 32 | # Compiled Static libraries 33 | *.lai 34 | *.la 35 | *.a 36 | *.lib 37 | 38 | # Executables 39 | *.exe 40 | *.out 41 | *.app 42 | main 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 oldjun 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #指定编译器 2 | CC = g++ 3 | 4 | #找出当前目录下,所有的源文件(以.cpp结尾) 5 | SRCS := $(shell find ./* -type f | grep '\.cpp' | grep -v '\.svn' | grep -v '\./plugin' | grep -v '\./log' | grep -v 'main\.cpp') 6 | $(warning SRCS is ${SRCS}) 7 | 8 | #确定cpp源文件对应的目标文件 9 | OBJS := $(patsubst %.cpp, %.o, $(filter %.cpp, $(SRCS))) 10 | $(warning OBJS is ${OBJS}) 11 | 12 | #编译选项 13 | CFLAGS = -g -O2 -Wall -Werror -Wno-unused -ldl -fPIC 14 | $(warning CFLAGS is ${CFLAGS}) 15 | 16 | #找出当前目录下所有头文件 17 | INCLUDE_TEMP = $(shell find ./* -type d | grep -v '\.svn' | grep -v '\./plugin' | grep -v '\./client' | grep -v '\./config' | grep -v '\./log') 18 | INCLUDE = $(patsubst %,-I %, $(INCLUDE_TEMP)) 19 | $(warning INCLUDE is ${INCLUDE}) 20 | 21 | LDFLAG = -lpthread -std=c++11 22 | 23 | #主程序 24 | SRC_MAIN = main.cpp 25 | OBJ_MAIN = ${SRC_MAIN:%.cpp=%.o} 26 | EXE_MAIN = main 27 | 28 | target: ${EXE_MAIN} 29 | $(EXE_MAIN): $(OBJ_MAIN) $(OBJS) 30 | $(CC) -o $@ $^ $(CFLAGS) $(INCLUDE) $(LDFLAG) 31 | 32 | %.o: %.cpp 33 | ${CC} ${CFLAGS} ${INCLUDE} -c $< -o $@ 34 | 35 | # test 插件 36 | PULGIN_TEST = plugin/testplugin.so 37 | SRC_PLUGIN_TEST = plugin/TestPlugin.cpp json/Parser.cpp json/Json.cpp 38 | 39 | # user 插件 40 | PLUGIN_USER = plugin/userplugin.so 41 | SRC_PLUGIN_USER = plugin/UserPlugin.cpp json/Parser.cpp json/Json.cpp 42 | 43 | # echo 插件 44 | PLUGIN_ECHO = plugin/echoplugin.so 45 | SRC_PLUGIN_ECHO = plugin/EchoPlugin.cpp utility/Logger.cpp utility/System.cpp 46 | 47 | ${PULGIN_TEST}: 48 | ${CC} -shared -fPIC ${INCLUDE} ${SRC_PLUGIN_TEST} -o ${PULGIN_TEST} 49 | 50 | ${PLUGIN_USER}: 51 | ${CC} -shared -fPIC ${INCLUDE} ${SRC_PLUGIN_USER} -o ${PLUGIN_USER} 52 | 53 | ${PLUGIN_ECHO}: 54 | ${CC} -shared -fPIC ${INCLUDE} ${SRC_PLUGIN_ECHO} -o ${PLUGIN_ECHO} 55 | 56 | plugin: ${PULGIN_TEST} ${PLUGIN_USER} ${PLUGIN_ECHO} 57 | 58 | clean: 59 | rm -f ${OBJS} ${OBJ_MAIN} ${EXE_MAIN} 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # yazi 2 | c++ framework 3 | -------------------------------------------------------------------------------- /client/php/client.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /engine/Context.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | using std::string; 4 | 5 | #include 6 | using std::map; 7 | 8 | namespace yazi { 9 | namespace engine { 10 | 11 | class Object 12 | { 13 | public: 14 | Object() {} 15 | virtual ~Object() {} 16 | }; 17 | 18 | 19 | class Context 20 | { 21 | public: 22 | Context() {} 23 | ~Context() { clear(); } 24 | 25 | template 26 | void set(const string &key, T value); 27 | 28 | template 29 | T get(const string &key); 30 | 31 | template 32 | T & ref(const string &key); 33 | 34 | void clear(); 35 | 36 | private: 37 | map m_bool; 38 | map m_char; 39 | map m_short; 40 | map m_int; 41 | map m_long; 42 | map m_double; 43 | map m_str; 44 | map m_obj; 45 | }; 46 | 47 | template<> 48 | inline void Context::set(const string &key, bool value) 49 | { 50 | m_bool[key] = value; 51 | } 52 | 53 | template<> 54 | inline bool Context::get(const string &key) 55 | { 56 | map::iterator it = m_bool.find(key); 57 | if (it != m_bool.end()) 58 | return it->second; 59 | 60 | return false; 61 | } 62 | 63 | template <> 64 | inline void Context::set(const string &key, char value) 65 | { 66 | m_char[key] = value; 67 | } 68 | 69 | template <> 70 | inline char Context::get(const string &key) 71 | { 72 | map::iterator it = m_char.find(key); 73 | if (it != m_char.end()) 74 | return it->second; 75 | return 0; 76 | } 77 | 78 | template <> 79 | inline void Context::set(const string &key, unsigned char value) 80 | { 81 | m_char[key] = value; 82 | } 83 | 84 | template <> 85 | inline unsigned char Context::get(const string &key) 86 | { 87 | map::iterator it = m_char.find(key); 88 | if (it != m_char.end()) 89 | return static_cast(it->second); 90 | return 0; 91 | } 92 | 93 | template <> 94 | inline void Context::set(const string &key, short value) 95 | { 96 | m_short[key] = value; 97 | } 98 | 99 | template <> 100 | inline short Context::get(const string &key) 101 | { 102 | map::iterator it = m_short.find(key); 103 | if (it != m_short.end()) 104 | return it->second; 105 | return 0; 106 | } 107 | 108 | template <> 109 | inline void Context::set(const string &key, unsigned short value) 110 | { 111 | m_short[key] = value; 112 | } 113 | 114 | template <> 115 | inline unsigned short Context::get(const string &key) 116 | { 117 | map::iterator it = m_short.find(key); 118 | if (it != m_short.end()) 119 | return static_cast(it->second); 120 | return 0; 121 | } 122 | 123 | template <> 124 | inline void Context::set(const string &key, int value) 125 | { 126 | m_int[key] = value; 127 | } 128 | 129 | template <> 130 | inline int Context::get(const string &key) 131 | { 132 | map::iterator it = m_int.find(key); 133 | if (it != m_int.end()) 134 | return it->second; 135 | return 0; 136 | } 137 | 138 | template <> 139 | inline void Context::set(const string &key, unsigned int value) 140 | { 141 | m_int[key] = value; 142 | } 143 | 144 | template <> 145 | inline unsigned int Context::get(const string &key) 146 | { 147 | map::iterator it = m_int.find(key); 148 | if (it != m_int.end()) 149 | return static_cast(it->second); 150 | return 0; 151 | } 152 | 153 | template <> 154 | inline void Context::set(const string &key, long value) 155 | { 156 | m_long[key] = value; 157 | } 158 | 159 | template <> 160 | inline long Context::get(const string &key) 161 | { 162 | map::iterator it = m_long.find(key); 163 | if (it != m_long.end()) 164 | return it->second; 165 | return 0; 166 | } 167 | 168 | template <> 169 | inline void Context::set(const string &key, unsigned long value) 170 | { 171 | m_long[key] = value; 172 | } 173 | 174 | template <> 175 | inline unsigned long Context::get(const string &key) 176 | { 177 | map::iterator it = m_long.find(key); 178 | if (it != m_long.end()) 179 | return static_cast(it->second); 180 | return 0; 181 | } 182 | 183 | template <> 184 | inline void Context::set(const string &key, double value) 185 | { 186 | m_double[key] = value; 187 | } 188 | 189 | template <> 190 | inline double Context::get(const string &key) 191 | { 192 | map::iterator it = m_double.find(key); 193 | if (it != m_double.end()) 194 | return it->second; 195 | return 0; 196 | } 197 | 198 | template <> 199 | inline void Context::set(const string &key, const string &value) 200 | { 201 | m_str[key] = value; 202 | } 203 | 204 | template <> 205 | inline string & Context::get(const string &key) 206 | { 207 | return m_str[key]; 208 | } 209 | 210 | template <> 211 | inline void Context::set(const string &key, Object* value) 212 | { 213 | m_obj[key] = value; 214 | } 215 | 216 | template <> 217 | inline Object * Context::get(const string &key) 218 | { 219 | map::iterator it = m_obj.find(key); 220 | if (it != m_obj.end()) 221 | return it->second; 222 | return NULL; 223 | } 224 | 225 | template <> 226 | inline string & Context::ref(const string &key) 227 | { 228 | return m_str[key]; 229 | } 230 | 231 | template 232 | inline T & Context::ref(const string &key) 233 | { 234 | map::iterator it = m_obj.find(key); 235 | if (it != m_obj.end()) 236 | { 237 | return *reinterpret_cast(it->second); 238 | } 239 | else 240 | { 241 | m_obj[key] = new T(); 242 | return *reinterpret_cast(m_obj[key]); 243 | } 244 | } 245 | 246 | inline void Context::clear() 247 | { 248 | m_bool.clear(); 249 | m_char.clear(); 250 | m_short.clear(); 251 | m_int.clear(); 252 | m_long.clear(); 253 | m_double.clear(); 254 | m_str.clear(); 255 | for (map::iterator it = m_obj.begin(); it != m_obj.end(); ++it) 256 | { 257 | delete it->second; 258 | it->second = NULL; 259 | } 260 | m_obj.clear(); 261 | } 262 | 263 | }} 264 | -------------------------------------------------------------------------------- /engine/Plugin.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | using namespace std; 4 | 5 | #include "Context.h" 6 | 7 | namespace yazi { 8 | namespace engine { 9 | 10 | class Plugin 11 | { 12 | public: 13 | Plugin() : m_name(""), m_switch(false) {} 14 | Plugin(const string & name, bool flag) : m_name(name), m_switch(flag) {} 15 | virtual ~Plugin() {} 16 | 17 | void set_name(const string & name) { m_name = name; } 18 | const string & get_name() const { return m_name; } 19 | 20 | void set_switch(bool flag) { m_switch = flag; } 21 | bool get_switch() const { return m_switch; } 22 | 23 | virtual bool run(Context & ctx) = 0; 24 | 25 | protected: 26 | string m_name; 27 | bool m_switch; 28 | }; 29 | 30 | #define DEFINE_PLUGIN(classType) \ 31 | extern "C" Plugin* create() \ 32 | { \ 33 | return new (std::nothrow) classType(); \ 34 | } \ 35 | extern "C" void destroy(Plugin *p) \ 36 | { \ 37 | delete p; \ 38 | p = NULL; \ 39 | } 40 | 41 | }} 42 | -------------------------------------------------------------------------------- /engine/PluginHelper.cpp: -------------------------------------------------------------------------------- 1 | #include "PluginHelper.h" 2 | using namespace yazi::engine; 3 | 4 | #include "Logger.h" 5 | #include "System.h" 6 | #include "Singleton.h" 7 | using namespace yazi::utility; 8 | 9 | 10 | PluginHelper::PluginHelper() 11 | { 12 | } 13 | 14 | PluginHelper::~PluginHelper() 15 | { 16 | } 17 | 18 | void PluginHelper::load(const string & plugin) 19 | { 20 | if (plugin.empty()) 21 | { 22 | error("load plugin failure: plugin is empty."); 23 | return; 24 | } 25 | if (m_plugins.find(plugin) != m_plugins.end()) 26 | { 27 | debug("plugin is already exist."); 28 | return; 29 | } 30 | 31 | System * sys = Singleton::instance(); 32 | string filename = sys->get_root_path() + "/plugin/" + plugin; 33 | void *handle = dlopen(filename.c_str(), RTLD_GLOBAL | RTLD_LAZY); 34 | if (handle == NULL) 35 | { 36 | error("load plugin failure: %s", dlerror()); 37 | return; 38 | } 39 | m_plugins[plugin] = handle; 40 | } 41 | 42 | void PluginHelper::unload(const string & plugin) 43 | { 44 | if (plugin.empty()) 45 | { 46 | error("unload plugin failure: plugin is empty."); 47 | return; 48 | } 49 | std::map::iterator it = m_plugins.find(plugin); 50 | if (it == m_plugins.end()) 51 | { 52 | error("unload plugin failure: plugin is not exist."); 53 | return; 54 | } 55 | dlclose(it->second); 56 | m_plugins.erase(it); 57 | } 58 | 59 | void * PluginHelper::get(const string & plugin, const string & symbol) 60 | { 61 | std::map::iterator it = m_plugins.find(plugin); 62 | if (it == m_plugins.end()) 63 | { 64 | load(plugin); 65 | it = m_plugins.find(plugin); 66 | if (it == m_plugins.end()) 67 | { 68 | error("load plugin failure: %s", plugin.c_str()); 69 | return NULL; 70 | } 71 | } 72 | 73 | void *func = dlsym(it->second, symbol.c_str()); 74 | if (func == NULL) 75 | { 76 | error("plugin: %s, undefined symbol: %s", plugin.c_str(), symbol.c_str()); 77 | } 78 | return func; 79 | } 80 | 81 | void PluginHelper::show() 82 | { 83 | for (std::map::iterator it = m_plugins.begin(); it != m_plugins.end(); ++it) 84 | { 85 | debug("plugin: name=%s handle=%x", it->first.c_str(), it->second); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /engine/PluginHelper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | using std::string; 7 | 8 | #include 9 | 10 | #include "Plugin.h" 11 | 12 | namespace yazi { 13 | namespace engine { 14 | 15 | typedef Plugin * (*create_func)(); 16 | typedef void (*destroy_func)(Plugin * plugin); 17 | 18 | 19 | class PluginHelper 20 | { 21 | public: 22 | PluginHelper(); 23 | ~PluginHelper(); 24 | 25 | void load(const string & plugin); 26 | void unload(const string & plugin); 27 | void * get(const string & plugin, const string & symbol); 28 | void show(); 29 | 30 | private: 31 | std::map m_plugins; 32 | }; 33 | 34 | }} 35 | -------------------------------------------------------------------------------- /engine/Work.cpp: -------------------------------------------------------------------------------- 1 | #include "Work.h" 2 | #include "Singleton.h" 3 | #include "PluginHelper.h" 4 | 5 | using namespace yazi::utility; 6 | using namespace yazi::engine; 7 | 8 | Work::Work() : m_name(""), m_switch(false) 9 | { 10 | } 11 | 12 | Work::Work(const string & name, bool flag) : m_name(name), m_switch(flag) 13 | { 14 | } 15 | 16 | Work::~Work() 17 | { 18 | for (vector::iterator it = m_plugins.begin(); it != m_plugins.end(); ++it) 19 | { 20 | destroy_func func = (destroy_func)Singleton::instance()->get((*it)->get_name(), "destroy"); 21 | func(dynamic_cast(*it)); 22 | } 23 | } 24 | 25 | void Work::append(Plugin* plugin) 26 | { 27 | m_plugins.push_back(plugin); 28 | } 29 | 30 | void Work::set_name(const string & name) 31 | { 32 | m_name = name; 33 | } 34 | 35 | const string & Work::get_name() const 36 | { 37 | return m_name; 38 | } 39 | 40 | void Work::set_switch(bool flag) 41 | { 42 | m_switch = flag; 43 | } 44 | 45 | bool Work::get_switch() const 46 | { 47 | return m_switch; 48 | } 49 | 50 | bool Work::run(Context & ctx) 51 | { 52 | for (std::vector::iterator it = m_plugins.begin(); it != m_plugins.end(); it++) 53 | { 54 | if ((*it)->get_switch()) 55 | { 56 | if (!(*it)->run(ctx)) { 57 | break; 58 | } 59 | } 60 | } 61 | 62 | return true; 63 | } 64 | -------------------------------------------------------------------------------- /engine/Work.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | using std::string; 5 | 6 | #include 7 | using std::vector; 8 | 9 | #include "Context.h" 10 | #include "Plugin.h" 11 | 12 | namespace yazi { 13 | namespace engine { 14 | 15 | class Work 16 | { 17 | public: 18 | Work(); 19 | Work(const string & name, bool flag); 20 | ~Work(); 21 | 22 | void append(Plugin * plugin); 23 | 24 | void set_name(const string &name); 25 | const string & get_name() const; 26 | 27 | void set_switch(bool flag); 28 | bool get_switch() const; 29 | 30 | bool run(Context & ctx); 31 | 32 | protected: 33 | string m_name; 34 | bool m_switch; 35 | vector m_plugins; 36 | }; 37 | 38 | }} 39 | -------------------------------------------------------------------------------- /engine/Workflow.cpp: -------------------------------------------------------------------------------- 1 | #include "Workflow.h" 2 | #include "Singleton.h" 3 | #include "Context.h" 4 | #include "Plugin.h" 5 | #include "PluginHelper.h" 6 | #include "Logger.h" 7 | 8 | using namespace yazi::utility; 9 | using namespace yazi::engine; 10 | 11 | 12 | Workflow::Workflow() 13 | { 14 | } 15 | 16 | Workflow::~Workflow() 17 | { 18 | for (map::iterator it = m_works.begin(); it != m_works.end(); ++it) 19 | { 20 | delete it->second; 21 | it->second = NULL; 22 | } 23 | m_works.clear(); 24 | } 25 | 26 | bool Workflow::load(const string &workinfo) 27 | { 28 | Document doc; 29 | doc.load_file(workinfo); 30 | Element root = doc.parse(); 31 | info("load workflow success: %s", workinfo.c_str()); 32 | 33 | for (Element::iterator it = root.begin(); it != root.end(); it++) 34 | { 35 | const string & name = it->attr("name"); 36 | const string & flag = it->attr("switch"); 37 | Work * work = new Work(); 38 | work->set_name(name); 39 | if (flag == "on") 40 | { 41 | work->set_switch(true); 42 | } 43 | else if (flag == "off") 44 | { 45 | work->set_switch(false); 46 | } 47 | else 48 | { 49 | error("plugin switch: %s is not supported: %s", name.c_str(), flag.c_str()); 50 | return false; 51 | } 52 | if (!load_plugin(work, (*it))) 53 | { 54 | return false; 55 | } 56 | m_works[name] = work; 57 | } 58 | return true; 59 | } 60 | 61 | bool Workflow::run(const string &work, const string &input, string &output) 62 | { 63 | std::map::iterator it = m_works.find(work); 64 | if (it == m_works.end()) 65 | { 66 | error("work: %s is not exist!", work.c_str()); 67 | return false; 68 | } 69 | if (!it->second->get_switch()) 70 | { 71 | error("work: %s is switch off!", work.c_str()); 72 | return false; 73 | } 74 | 75 | Context ctx; 76 | ctx.ref("input") = input; 77 | if (!it->second->run(ctx)) 78 | { 79 | error("work: %s run error!", work.c_str()); 80 | return false; 81 | } 82 | output = ctx.ref("output"); 83 | return true; 84 | } 85 | 86 | bool Workflow::load_plugin(Work* work, Element & elem) 87 | { 88 | for (Element::iterator it = elem.begin(); it != elem.end(); it++) 89 | { 90 | if (it->name() != "plugin") 91 | { 92 | error("plugin %s elem: %s is not supported", it->attr("name").c_str(), it->name().c_str()); 93 | return false; 94 | } 95 | const string & name = it->attr("name"); 96 | create_func func = (create_func)Singleton::instance()->get(name, "create"); 97 | Plugin *plugin = func(); 98 | plugin->set_name(name); 99 | 100 | const string & flag = it->attr("switch"); 101 | if (flag == "on") 102 | plugin->set_switch(true); 103 | else if (flag == "off") 104 | plugin->set_switch(false); 105 | else 106 | { 107 | error("plugin %s switch: %s is not supported", name.c_str(), flag.c_str()); 108 | return false; 109 | } 110 | work->append(plugin); 111 | } 112 | return true; 113 | } 114 | 115 | -------------------------------------------------------------------------------- /engine/Workflow.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | using std::string; 5 | 6 | #include "Document.h" 7 | #include "Element.h" 8 | using namespace yazi::xml; 9 | 10 | #include "Work.h" 11 | 12 | namespace yazi { 13 | namespace engine { 14 | 15 | class Workflow 16 | { 17 | public: 18 | Workflow(); 19 | ~Workflow(); 20 | 21 | bool load(const string &workinfo); 22 | bool run(const string &work, const string &input, string &output); 23 | 24 | private: 25 | bool load_plugin(Work* work, Element & elem); 26 | 27 | private: 28 | std::map m_works; 29 | }; 30 | 31 | }} 32 | -------------------------------------------------------------------------------- /json/Json.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using std::istringstream; 4 | using std::ostringstream; 5 | 6 | #include 7 | 8 | #include "Json.h" 9 | #include "Parser.h" 10 | using namespace yazi::json; 11 | 12 | Json::Json() : m_type(json_null), m_int(0), m_double(0.0), m_bool(false) 13 | { 14 | } 15 | 16 | Json::Json(Type type) : m_type(type), m_int(0), m_double(0.0), m_bool(false) 17 | { 18 | } 19 | 20 | Json::Json(bool value) 21 | { 22 | m_type = json_bool; 23 | m_bool = value; 24 | } 25 | 26 | Json::Json(int value) 27 | { 28 | m_type = json_int; 29 | m_int = value; 30 | } 31 | 32 | Json::Json(double value) 33 | { 34 | m_type = json_double; 35 | m_double = value; 36 | } 37 | 38 | Json::Json(const char * value) 39 | { 40 | m_type = json_string; 41 | m_string = value; 42 | } 43 | 44 | Json::Json(const string & value) 45 | { 46 | m_type = json_string; 47 | m_string = value; 48 | } 49 | 50 | Json::Json(const Json & other) 51 | { 52 | copy(other); 53 | } 54 | 55 | Json::~Json() 56 | { 57 | clear(); 58 | } 59 | 60 | Json::Type Json::type() const 61 | { 62 | return m_type; 63 | } 64 | 65 | bool Json::isNull() const 66 | { 67 | return (type() == json_null); 68 | } 69 | 70 | bool Json::isBool() const 71 | { 72 | return (type() == json_bool); 73 | } 74 | 75 | bool Json::isInt() const 76 | { 77 | return (type() == json_int); 78 | } 79 | 80 | bool Json::isDouble() const 81 | { 82 | return (type() == json_double); 83 | } 84 | 85 | bool Json::isString() const 86 | { 87 | return (type() == json_string); 88 | } 89 | 90 | bool Json::isArray() const 91 | { 92 | return (type() == json_array); 93 | } 94 | 95 | bool Json::isObject() const 96 | { 97 | return (type() == json_object); 98 | } 99 | 100 | bool Json::asBool() const 101 | { 102 | switch (type()) 103 | { 104 | case json_bool: 105 | return m_bool; 106 | default: 107 | break; 108 | } 109 | throw std::logic_error("function Json::asBool value type error"); 110 | } 111 | 112 | int Json::asInt() const 113 | { 114 | switch (type()) 115 | { 116 | case json_int: 117 | return m_int; 118 | default: 119 | break; 120 | } 121 | throw std::logic_error("function Json::asInt value type error"); 122 | } 123 | 124 | double Json::asDouble() const 125 | { 126 | switch (type()) 127 | { 128 | case json_double: 129 | return m_double; 130 | default: 131 | break; 132 | } 133 | throw std::logic_error("function Json::asDouble value type error"); 134 | } 135 | 136 | string Json::asString() const 137 | { 138 | switch (type()) 139 | { 140 | case json_string: 141 | return m_string; 142 | default: 143 | break; 144 | } 145 | throw std::logic_error("function Json::asString value type error"); 146 | } 147 | 148 | void Json::copy(const Json & other) 149 | { 150 | clear(); 151 | 152 | m_type = other.type(); 153 | 154 | switch (other.type()) 155 | { 156 | case json_null: 157 | break; 158 | case json_int: 159 | m_int = other.m_int; 160 | break; 161 | case json_double: 162 | m_double = other.m_double; 163 | break; 164 | case json_bool: 165 | m_bool = other.m_bool; 166 | break; 167 | case json_string: 168 | m_string = other.m_string; 169 | break; 170 | case json_array: 171 | m_array = other.m_array; 172 | break; 173 | case json_object: 174 | m_object = other.m_object; 175 | break; 176 | default: 177 | break; 178 | } 179 | } 180 | 181 | int Json::size() const 182 | { 183 | switch (type()) 184 | { 185 | case json_array: 186 | return m_array.size(); 187 | case json_object: 188 | return m_object.size(); 189 | default: 190 | break; 191 | } 192 | throw std::logic_error("function Json::size value type error"); 193 | } 194 | 195 | bool Json::empty() const 196 | { 197 | switch (type()) 198 | { 199 | case json_null: 200 | return true; 201 | case json_array: 202 | return m_array.empty(); 203 | case json_object: 204 | return m_object.empty(); 205 | default: 206 | break; 207 | } 208 | throw std::logic_error("function Json::empty value type error"); 209 | } 210 | 211 | void Json::clear() 212 | { 213 | m_int = 0; 214 | m_double = 0.0; 215 | m_bool = false; 216 | m_string.clear(); 217 | m_array.clear(); 218 | m_object.clear(); 219 | } 220 | 221 | bool Json::remove(int index) 222 | { 223 | if (type() != json_array) 224 | { 225 | return false; 226 | } 227 | int size = m_array.size(); 228 | if (index < 0 || index >= size) 229 | { 230 | return false; 231 | } 232 | m_array.erase(m_array.begin() + index); 233 | return true; 234 | } 235 | 236 | bool Json::remove(const char * key) 237 | { 238 | string name = key; 239 | return remove(name); 240 | } 241 | 242 | bool Json::remove(const string & key) 243 | { 244 | if (type() != json_object) 245 | { 246 | return false; 247 | } 248 | std::map::iterator it = m_object.find(key); 249 | if (it == m_object.end()) 250 | { 251 | return false; 252 | } 253 | m_object.erase(it); 254 | return true; 255 | } 256 | 257 | bool Json::has(int index) 258 | { 259 | if (type() != json_array) 260 | { 261 | return false; 262 | } 263 | int size = m_array.size(); 264 | return (index >= 0 && index < size); 265 | } 266 | 267 | bool Json::has(const char * key) 268 | { 269 | string name(key); 270 | return has(name); 271 | } 272 | 273 | bool Json::has(const string & key) 274 | { 275 | if (type() != json_object) 276 | { 277 | return false; 278 | } 279 | std::map::const_iterator it = m_object.find(key); 280 | return (it != m_object.end()); 281 | } 282 | 283 | const Json & Json::get(int index) const 284 | { 285 | if (type() != json_array) 286 | { 287 | throw std::logic_error("function Json::get [int] requires array value"); 288 | } 289 | int size = m_array.size(); 290 | if (index >= 0 && index < size) 291 | { 292 | return m_array.at(index); 293 | } 294 | return null(); 295 | } 296 | 297 | const Json & Json::get(const char * key) const 298 | { 299 | const string name = key; 300 | return get(name); 301 | } 302 | 303 | const Json & Json::get(const string & key) const 304 | { 305 | if (type() != json_object) 306 | { 307 | throw std::logic_error("function Json::get [const string &] requires object value"); 308 | } 309 | std::map::const_iterator it = m_object.find(key); 310 | if (it != m_object.end()) 311 | { 312 | return it->second; 313 | } 314 | return null(); 315 | } 316 | 317 | void Json::set(const Json & other) 318 | { 319 | copy(other); 320 | } 321 | 322 | void Json::set(bool value) 323 | { 324 | clear(); 325 | m_type = json_bool; 326 | m_bool = value; 327 | } 328 | 329 | void Json::set(int value) 330 | { 331 | clear(); 332 | m_type = json_int; 333 | m_int = value; 334 | } 335 | 336 | void Json::set(double value) 337 | { 338 | clear(); 339 | m_type = json_double; 340 | m_double = value; 341 | } 342 | 343 | void Json::set(const string & value) 344 | { 345 | clear(); 346 | m_type = json_string; 347 | m_string = value; 348 | } 349 | 350 | void Json::set(const char * value) 351 | { 352 | clear(); 353 | m_type = json_string; 354 | m_string = value; 355 | } 356 | 357 | Json & Json::append(const Json & value) 358 | { 359 | if (type() == json_null) 360 | { 361 | m_type = json_array; 362 | } 363 | if (type() != json_array) 364 | { 365 | throw std::logic_error("function Json::append requires array value"); 366 | } 367 | m_array.push_back(value); 368 | return (*this); 369 | } 370 | 371 | Json & Json::operator = (const Json& other) 372 | { 373 | copy(other); 374 | return *this; 375 | } 376 | 377 | Json & Json::operator = (bool value) 378 | { 379 | Json other(value); 380 | copy(other); 381 | return *this; 382 | } 383 | 384 | Json & Json::operator = (int value) 385 | { 386 | Json other(value); 387 | copy(other); 388 | return *this; 389 | } 390 | 391 | Json & Json::operator = (double value) 392 | { 393 | Json other(value); 394 | copy(other); 395 | return *this; 396 | } 397 | 398 | Json & Json::operator = (const string & value) 399 | { 400 | Json other(value); 401 | copy(other); 402 | return *this; 403 | } 404 | 405 | Json & Json::operator = (const char * value) 406 | { 407 | Json other(value); 408 | copy(other); 409 | return *this; 410 | } 411 | 412 | bool Json::operator == (const Json & other) 413 | { 414 | if (type() != other.type()) 415 | { 416 | return false; 417 | } 418 | switch (type()) 419 | { 420 | case json_null: 421 | return true; 422 | case json_bool: 423 | return (m_bool == other.m_bool); 424 | case json_int: 425 | return (m_int == other.m_int); 426 | case json_double: 427 | return (m_double == other.m_double); 428 | case json_string: 429 | return (m_string == other.m_string); 430 | default: 431 | break; 432 | } 433 | return false; 434 | } 435 | 436 | bool Json::operator == (bool value) 437 | { 438 | Json other = value; 439 | return (*this == other); 440 | } 441 | 442 | bool Json::operator == (int value) 443 | { 444 | Json other = value; 445 | return (*this == other); 446 | } 447 | 448 | bool Json::operator == (double value) 449 | { 450 | Json other = value; 451 | return (*this == other); 452 | } 453 | 454 | bool Json::operator == (const string & value) 455 | { 456 | Json other = value; 457 | return (*this == other); 458 | } 459 | 460 | bool Json::operator == (const char * value) 461 | { 462 | Json other = value; 463 | return (*this == other); 464 | } 465 | 466 | bool Json::operator != (const Json & other) 467 | { 468 | return !(*this == other); 469 | } 470 | 471 | 472 | bool Json::operator != (bool value) 473 | { 474 | Json other = value; 475 | return (*this != other); 476 | } 477 | 478 | bool Json::operator != (int value) 479 | { 480 | Json other = value; 481 | return (*this != other); 482 | } 483 | 484 | bool Json::operator != (double value) 485 | { 486 | Json other = value; 487 | return (*this != other); 488 | } 489 | 490 | bool Json::operator != (const string & value) 491 | { 492 | Json other = value; 493 | return (*this != other); 494 | } 495 | 496 | bool Json::operator != (const char * value) 497 | { 498 | Json other = string(value); 499 | return (*this != other); 500 | } 501 | 502 | Json & Json::operator [] (int index) 503 | { 504 | if (type() == json_null) 505 | { 506 | m_type = json_array; 507 | } 508 | if (type() != json_array) 509 | { 510 | throw std::logic_error("function Json::operator [int] requires array value"); 511 | } 512 | int size = m_array.size(); 513 | if (index < 0) 514 | { 515 | throw std::logic_error("function Json::operator [int] index less 0"); 516 | } 517 | if (index > 0 && index < size) 518 | { 519 | return m_array.at(index); 520 | } 521 | if (index >= size) 522 | { 523 | for (int i = size; i <= index; i++) 524 | { 525 | m_array.push_back(Json()); 526 | } 527 | } 528 | return m_array.at(index); 529 | } 530 | 531 | const Json & Json::operator [] (int index) const 532 | { 533 | return get(index); 534 | } 535 | 536 | Json & Json::operator [] (const char * key) 537 | { 538 | string name = key; 539 | return (*this)[name]; 540 | } 541 | 542 | Json & Json::operator [] (const string & key) 543 | { 544 | if (type() == json_null) 545 | { 546 | m_type = json_object; 547 | } 548 | if (type() != json_object) 549 | { 550 | throw std::logic_error("function Json::operator [const string &] requires object value"); 551 | } 552 | return m_object[key]; 553 | } 554 | 555 | const Json & Json::operator [] (const char * key) const 556 | { 557 | return get(key); 558 | } 559 | 560 | const Json & Json::operator [] (const string & key) const 561 | { 562 | return get(key); 563 | } 564 | 565 | Json::operator bool() 566 | { 567 | if (type() != json_bool) 568 | { 569 | throw std::logic_error("function Json::operator (bool) requires bool value"); 570 | } 571 | return m_bool; 572 | } 573 | 574 | Json::operator int() 575 | { 576 | if (type() != json_int) 577 | { 578 | throw std::logic_error("function Json::operator (int) requires int value"); 579 | } 580 | return m_int; 581 | } 582 | 583 | Json::operator double() 584 | { 585 | if (type() != json_double) 586 | { 587 | throw std::logic_error("function Json::operator (double) requires double value"); 588 | } 589 | return m_double; 590 | } 591 | 592 | Json::operator string () 593 | { 594 | if (type() != json_string) 595 | { 596 | throw std::logic_error("function Json::operator (string) requires string value"); 597 | } 598 | return m_string; 599 | } 600 | 601 | Json::operator string () const 602 | { 603 | if (type() != json_string) 604 | { 605 | throw std::logic_error("function Json::operator (string) requires string value"); 606 | } 607 | return m_string; 608 | } 609 | 610 | Json const & Json::null() 611 | { 612 | static const Json null; 613 | return null; 614 | } 615 | 616 | void Json::parse(const string & str) 617 | { 618 | Parser parser; 619 | parser.load(str); 620 | *this = parser.parse(); 621 | } 622 | 623 | string Json::toString() const 624 | { 625 | ostringstream os; 626 | switch (type()) 627 | { 628 | case json_null: 629 | os << "null"; 630 | break; 631 | case json_bool: 632 | if (m_bool) 633 | { 634 | os << "true"; 635 | } 636 | else 637 | { 638 | os << "false"; 639 | } 640 | break; 641 | case json_int: 642 | os << m_int; 643 | break; 644 | case json_double: 645 | os << m_double; 646 | break; 647 | case json_string: 648 | os << "\"" << m_string << "\""; 649 | break; 650 | case json_array: 651 | { 652 | os << "["; 653 | for (std::vector::const_iterator it = m_array.begin(); it != m_array.end(); it++) 654 | { 655 | if (it != m_array.begin()) 656 | { 657 | os << ","; 658 | } 659 | os << (*it).toString(); 660 | } 661 | os << "]"; 662 | } 663 | break; 664 | case json_object: 665 | { 666 | os << "{"; 667 | for (std::map::const_iterator it = m_object.begin(); it != m_object.end(); it++) 668 | { 669 | if (it != m_object.begin()) 670 | { 671 | os << ","; 672 | } 673 | os << "\"" << it->first << "\":" << it->second.toString(); 674 | } 675 | os << "}"; 676 | return os.str(); 677 | } 678 | break; 679 | default: 680 | break; 681 | } 682 | return os.str(); 683 | } -------------------------------------------------------------------------------- /json/Json.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | using std::string; 5 | 6 | #include 7 | #include 8 | 9 | 10 | namespace yazi { 11 | namespace json { 12 | 13 | class Json 14 | { 15 | public: 16 | enum Type 17 | { 18 | json_null = 0, ///< 'null' value 19 | json_bool, ///< bool value 20 | json_int, ///< integer value 21 | json_double, ///< double value 22 | json_string, ///< UTF-8 string value 23 | json_array, ///< array value (ordered list) 24 | json_object ///< object value (collection of name/value pairs). 25 | }; 26 | 27 | Json(); 28 | Json(Type type); 29 | Json(bool value); 30 | Json(int value); 31 | Json(double value); 32 | Json(const char * value); 33 | Json(const string & value); 34 | Json(const Json & other); 35 | ~Json(); 36 | 37 | Type type() const; 38 | 39 | bool isNull() const; 40 | bool isBool() const; 41 | bool isInt() const; 42 | bool isDouble() const; 43 | bool isString() const; 44 | bool isArray() const; 45 | bool isObject() const; 46 | 47 | bool asBool() const; 48 | int asInt() const; 49 | double asDouble() const; 50 | string asString() const; 51 | 52 | void copy(const Json & other); 53 | 54 | // number of values in array or object 55 | int size() const; 56 | 57 | 58 | // return true if empty array, empty object, or null, otherwise, false. 59 | bool empty() const; 60 | 61 | void clear(); 62 | 63 | bool remove(int index); 64 | bool remove(const char * key); 65 | bool remove(const string & key); 66 | 67 | bool has(int index); 68 | bool has(const char * key); 69 | bool has(const string & key); 70 | 71 | const Json & get(int index) const; 72 | const Json & get(const char * key) const; 73 | const Json & get(const string & key) const; 74 | 75 | void set(const Json & other); 76 | void set(bool value); 77 | void set(int value); 78 | void set(double value); 79 | void set(const string & value); 80 | void set(const char * value); 81 | 82 | // Append value to array at the end. 83 | // Equivalent to m_array[m_array.size()] = value; 84 | Json & append(const Json & value); 85 | 86 | Json & operator = (const Json & other); 87 | Json & operator = (bool value); 88 | Json & operator = (int value); 89 | Json & operator = (double value); 90 | Json & operator = (const string & value); 91 | Json & operator = (const char * value); 92 | 93 | bool operator == (const Json & other); 94 | bool operator == (bool value); 95 | bool operator == (int value); 96 | bool operator == (double value); 97 | bool operator == (const string & value); 98 | bool operator == (const char * value); 99 | 100 | bool operator != (const Json & other); 101 | bool operator != (bool value); 102 | bool operator != (int value); 103 | bool operator != (double value); 104 | bool operator != (const string & value); 105 | bool operator != (const char * value); 106 | 107 | // Access an array element (zero based index) 108 | Json & operator [] (int index); 109 | // Access an array element (zero based index), returns null if there is no member with that name. 110 | const Json & operator [] (int index) const; 111 | 112 | // Access an object value by name, create a null member if it does not exist. 113 | Json & operator [] (const char * key); 114 | // Access an object value by name, returns null if there is no member with that name. 115 | const Json & operator [] (const char * key) const; 116 | 117 | // Access an object value by name, create a null member if it does not exist. 118 | Json & operator [] (const string & key); 119 | // Access an object value by name, returns null if there is no member with that name. 120 | const Json & operator [] (const string & key) const; 121 | 122 | operator bool(); 123 | operator int(); 124 | operator double(); 125 | operator string(); 126 | operator string() const; 127 | 128 | // static 129 | static Json const & null(); 130 | 131 | void parse(const string & str); 132 | string toString() const; 133 | 134 | typedef std::vector::iterator iterator; 135 | typedef std::vector::const_iterator const_iterator; 136 | 137 | iterator begin() 138 | { 139 | return m_array.begin(); 140 | } 141 | 142 | iterator end() 143 | { 144 | return m_array.end(); 145 | } 146 | 147 | const_iterator begin() const 148 | { 149 | return m_array.begin(); 150 | } 151 | 152 | const_iterator end() const 153 | { 154 | return m_array.end(); 155 | } 156 | 157 | private: 158 | Type m_type; 159 | 160 | int m_int; 161 | double m_double; 162 | bool m_bool; 163 | std::string m_string; 164 | std::vector m_array; 165 | std::map m_object; 166 | }; 167 | 168 | }} -------------------------------------------------------------------------------- /json/Parser.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "Parser.h" 5 | 6 | using namespace yazi::json; 7 | 8 | Parser::Parser() : m_idx(0) 9 | { 10 | 11 | } 12 | 13 | Parser::~Parser() 14 | { 15 | 16 | } 17 | 18 | void Parser::load(const string & str) 19 | { 20 | m_str = str; 21 | m_idx = 0; 22 | } 23 | 24 | void Parser::skip_white_spaces() 25 | { 26 | while (m_str[m_idx] == ' ' || m_str[m_idx] == '\r' || m_str[m_idx] == '\n' || m_str[m_idx] == '\t') 27 | m_idx++; 28 | } 29 | 30 | char Parser::get_next_token() 31 | { 32 | skip_white_spaces(); 33 | if (m_idx == m_str.size()) 34 | throw std::logic_error("unexpected end of input"); 35 | return m_str[m_idx++]; 36 | } 37 | 38 | Json Parser::parse() 39 | { 40 | char ch = get_next_token(); 41 | 42 | if (ch == 'n') 43 | { 44 | m_idx--; 45 | return parse_null(); 46 | } 47 | 48 | if (ch == 't' || ch == 'f') 49 | { 50 | m_idx--; 51 | return parse_bool(); 52 | } 53 | 54 | if (ch == '-' || (ch >= '0' && ch <= '9')) 55 | { 56 | m_idx--; 57 | return parse_number(); 58 | } 59 | 60 | if (ch == '"') 61 | { 62 | return parse_string(); 63 | } 64 | 65 | if (ch == '[') 66 | { 67 | Json arr(Json::json_array); 68 | ch = get_next_token(); 69 | if (ch == ']') 70 | { 71 | return arr; 72 | } 73 | while (true) 74 | { 75 | m_idx--; 76 | arr.append(parse()); 77 | ch = get_next_token(); 78 | if (ch == ']') 79 | { 80 | break; 81 | } 82 | if (ch != ',') 83 | { 84 | throw std::logic_error("expected ',' in array"); 85 | } 86 | ch = get_next_token(); 87 | } 88 | return arr; 89 | } 90 | 91 | 92 | if (ch == '{') 93 | { 94 | Json obj(Json::json_object); 95 | ch = get_next_token(); 96 | if (ch == '}') 97 | { 98 | return obj; 99 | } 100 | 101 | while (true) 102 | { 103 | if (ch != '"') 104 | { 105 | throw std::logic_error("expected '\"' in object"); 106 | } 107 | string key = parse_string(); 108 | 109 | ch = get_next_token(); 110 | if (ch != ':') 111 | { 112 | throw std::logic_error("expected ':' in object"); 113 | } 114 | 115 | obj[key] = parse(); 116 | 117 | ch = get_next_token(); 118 | if (ch == '}') 119 | { 120 | break; 121 | } 122 | if (ch != ',') 123 | { 124 | throw std::logic_error("expected ',' in object"); 125 | } 126 | ch = get_next_token(); 127 | } 128 | return obj; 129 | } 130 | 131 | throw std::logic_error("unexpected character in parse json"); 132 | } 133 | 134 | Json Parser::parse_null() 135 | { 136 | if (m_str.compare(m_idx, 4, "null") == 0) 137 | { 138 | m_idx += 4; 139 | return Json(); 140 | } 141 | throw std::logic_error("parse null error"); 142 | } 143 | 144 | Json Parser::parse_bool() 145 | { 146 | if (m_str.compare(m_idx, 4, "true") == 0) 147 | { 148 | m_idx += 4; 149 | return Json(true); 150 | } 151 | if (m_str.compare(m_idx, 5, "false") == 0) 152 | { 153 | m_idx += 5; 154 | return Json(false); 155 | } 156 | throw std::logic_error("parse bool error"); 157 | } 158 | 159 | Json Parser::parse_number() 160 | { 161 | size_t pos = m_idx; 162 | 163 | if (m_str[m_idx] == '-') 164 | m_idx++; 165 | 166 | // integer part 167 | if (m_str[m_idx] == '0') 168 | { 169 | m_idx++; 170 | if (in_range(m_str[m_idx], '0', '9')) 171 | { 172 | throw std::logic_error("leading 0s not permitted in numbers"); 173 | } 174 | } 175 | else if (in_range(m_str[m_idx], '1', '9')) 176 | { 177 | m_idx++; 178 | while (in_range(m_str[m_idx], '0', '9')) 179 | { 180 | m_idx++; 181 | } 182 | } 183 | else 184 | { 185 | throw std::logic_error("invalid character in number"); 186 | } 187 | 188 | if (m_str[m_idx] != '.') 189 | { 190 | return std::atoi(m_str.c_str() + pos); 191 | } 192 | 193 | // decimal part 194 | if (m_str[m_idx] == '.') 195 | { 196 | m_idx++; 197 | if (!in_range(m_str[m_idx], '0', '9')) 198 | { 199 | throw std::logic_error("at least one digit required in fractional part"); 200 | } 201 | while (in_range(m_str[m_idx], '0', '9')) 202 | { 203 | m_idx++; 204 | } 205 | } 206 | 207 | return std::atof(m_str.c_str() + pos); 208 | } 209 | 210 | Json Parser::parse_string() 211 | { 212 | string out; 213 | while (true) 214 | { 215 | if (m_idx == m_str.size()) 216 | { 217 | throw std::logic_error("unexpected end of input in string"); 218 | } 219 | 220 | char ch = m_str[m_idx++]; 221 | if (ch == '"') 222 | { 223 | return out; 224 | } 225 | 226 | // The usual case: non-escaped characters 227 | if (ch != '\\') 228 | { 229 | out += ch; 230 | continue; 231 | } 232 | 233 | // Handle escapes 234 | throw std::logic_error("not support escaped characters in string"); 235 | } 236 | } 237 | 238 | -------------------------------------------------------------------------------- /json/Parser.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | using namespace std; 5 | 6 | #include "Json.h" 7 | 8 | namespace yazi { 9 | namespace json { 10 | 11 | class Parser 12 | { 13 | public: 14 | Parser(); 15 | ~Parser(); 16 | 17 | void load(const string & str); 18 | Json parse(); 19 | 20 | private: 21 | void skip_white_spaces(); 22 | char get_next_token(); 23 | 24 | Json parse_null(); 25 | Json parse_bool(); 26 | Json parse_number(); 27 | Json parse_string(); 28 | 29 | bool in_range(long x, long lower, long upper) 30 | { 31 | return (x >= lower && x <= upper); 32 | } 33 | 34 | private: 35 | string m_str; 36 | size_t m_idx; 37 | }; 38 | 39 | }} 40 | -------------------------------------------------------------------------------- /kill.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ps -ef|grep main|grep -v grep|grep -v vscode|awk -F ' ' '{print $2}'|xargs kill -9 4 | 5 | rm -rf log/*.log 6 | 7 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | #include "System.h" 5 | #include "IniFile.h" 6 | #include "Singleton.h" 7 | using namespace yazi::utility; 8 | 9 | #include "Server.h" 10 | using namespace yazi::server; 11 | 12 | 13 | int main() 14 | { 15 | System * sys = Singleton::instance(); 16 | sys->init(); 17 | 18 | IniFile * ini = Singleton::instance(); 19 | const string & ip = (*ini)["server"]["ip"]; 20 | int port = (*ini)["server"]["port"]; 21 | int threads = (*ini)["server"]["threads"]; 22 | int max_conn = (*ini)["server"]["max_conn"]; 23 | int wait_time = (*ini)["server"]["wait_time"]; 24 | 25 | Server * server = Singleton::instance(); 26 | server->set_threads(threads); 27 | server->set_connects(max_conn); 28 | server->set_wait_time(wait_time); 29 | 30 | server->listen(ip, port); 31 | server->start(); 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /plugin/EchoPlugin.cpp: -------------------------------------------------------------------------------- 1 | #include "EchoPlugin.h" 2 | using namespace yazi::engine; 3 | using namespace yazi::plugin; 4 | 5 | #include "Logger.h" 6 | #include "Singleton.h" 7 | #include "System.h" 8 | using namespace yazi::utility; 9 | 10 | 11 | 12 | EchoPlugin::EchoPlugin() : Plugin() 13 | { 14 | System * sys = Singleton::instance(); 15 | const string & root_path = sys->get_root_path(); 16 | 17 | // init logger 18 | Logger::instance()->open(root_path + "/log/echo.log"); 19 | } 20 | 21 | EchoPlugin::~EchoPlugin() 22 | { 23 | 24 | } 25 | 26 | bool EchoPlugin::run(Context & ctx) 27 | { 28 | string & input = ctx.ref("input"); 29 | info(input.c_str()); 30 | ctx.ref("output") = input + " echo plugin run!"; 31 | return true; 32 | } -------------------------------------------------------------------------------- /plugin/EchoPlugin.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Plugin.h" 4 | using namespace yazi::engine; 5 | 6 | namespace yazi { 7 | namespace plugin { 8 | 9 | class EchoPlugin : public Plugin 10 | { 11 | public: 12 | EchoPlugin(); 13 | virtual ~EchoPlugin(); 14 | 15 | virtual bool run(Context & ctx); 16 | 17 | }; 18 | 19 | DEFINE_PLUGIN(EchoPlugin) 20 | 21 | }} -------------------------------------------------------------------------------- /plugin/TestPlugin.cpp: -------------------------------------------------------------------------------- 1 | #include "TestPlugin.h" 2 | using namespace yazi::engine; 3 | using namespace yazi::plugin; 4 | 5 | 6 | TestPlugin::TestPlugin() : Plugin() 7 | { 8 | 9 | } 10 | 11 | TestPlugin::~TestPlugin() 12 | { 13 | 14 | } 15 | 16 | bool TestPlugin::run(Context & ctx) 17 | { 18 | string & input = ctx.ref("input"); 19 | ctx.ref("output") = input + " test plugin run!\n"; 20 | return false; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /plugin/TestPlugin.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Plugin.h" 4 | using namespace yazi::engine; 5 | 6 | namespace yazi { 7 | namespace plugin { 8 | 9 | class TestPlugin : public Plugin 10 | { 11 | public: 12 | TestPlugin(); 13 | virtual ~TestPlugin(); 14 | 15 | virtual bool run(Context & ctx); 16 | 17 | }; 18 | 19 | DEFINE_PLUGIN(TestPlugin) 20 | 21 | }} 22 | -------------------------------------------------------------------------------- /plugin/UserPlugin.cpp: -------------------------------------------------------------------------------- 1 | #include "UserPlugin.h" 2 | using namespace yazi::engine; 3 | using namespace yazi::plugin; 4 | 5 | #include "Json.h" 6 | using namespace yazi::json; 7 | 8 | UserPlugin::UserPlugin() : Plugin() 9 | { 10 | 11 | } 12 | 13 | UserPlugin::~UserPlugin() 14 | { 15 | 16 | } 17 | 18 | bool UserPlugin::run(Context & ctx) 19 | { 20 | string & input = ctx.ref("input"); 21 | ctx.ref("output") += "user plugin run!"; 22 | return true; 23 | } 24 | 25 | -------------------------------------------------------------------------------- /plugin/UserPlugin.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Plugin.h" 4 | using namespace yazi::engine; 5 | 6 | namespace yazi { 7 | namespace plugin { 8 | 9 | class UserPlugin : public Plugin 10 | { 11 | public: 12 | UserPlugin(); 13 | virtual ~UserPlugin(); 14 | 15 | virtual bool run(Context & ctx); 16 | 17 | }; 18 | 19 | DEFINE_PLUGIN(UserPlugin) 20 | 21 | }} 22 | -------------------------------------------------------------------------------- /server/Server.cpp: -------------------------------------------------------------------------------- 1 | #include "Server.h" 2 | using namespace yazi::server; 3 | 4 | #include "Singleton.h" 5 | using namespace yazi::utility; 6 | 7 | #include "TaskDispatcher.h" 8 | using namespace yazi::thread; 9 | 10 | #include "SocketHandler.h" 11 | using namespace yazi::socket; 12 | 13 | Server::Server() : m_ip(""), m_port(0), m_threads(1024), m_connects(1024), m_wait_time(10) 14 | { 15 | } 16 | 17 | Server::~Server() 18 | { 19 | } 20 | 21 | void Server::listen(const string & ip, int port) 22 | { 23 | m_ip = ip; 24 | m_port = port; 25 | } 26 | 27 | void Server::start() 28 | { 29 | // init the thread pool and task queue 30 | TaskDispatcher * dispatcher = Singleton::instance(); 31 | dispatcher->init(m_threads); 32 | 33 | // init the socket handler 34 | SocketHandler * socket_handler = Singleton::instance(); 35 | socket_handler->listen(m_ip, m_port); 36 | socket_handler->handle(m_connects, m_wait_time); 37 | } 38 | 39 | void Server::set_threads(int threads) 40 | { 41 | m_threads = threads; 42 | } 43 | 44 | void Server::set_connects(int connects) 45 | { 46 | m_connects = connects; 47 | } 48 | 49 | void Server::set_wait_time(int wait_time) 50 | { 51 | m_wait_time = wait_time; 52 | } 53 | 54 | -------------------------------------------------------------------------------- /server/Server.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | using namespace std; 5 | 6 | namespace yazi { 7 | namespace server { 8 | 9 | class Server 10 | { 11 | public: 12 | Server(); 13 | ~Server(); 14 | 15 | void listen(const string & ip, int port); 16 | void start(); 17 | void set_threads(int threads); 18 | void set_connects(int connects); 19 | void set_wait_time(int wait_time); 20 | 21 | private: 22 | string m_ip; 23 | int m_port; 24 | int m_threads; 25 | int m_connects; 26 | int m_wait_time; 27 | }; 28 | 29 | }} 30 | -------------------------------------------------------------------------------- /socket/ClientSocket.cpp: -------------------------------------------------------------------------------- 1 | #include "ClientSocket.h" 2 | #include "Logger.h" 3 | using namespace yazi::utility; 4 | using namespace yazi::socket; 5 | 6 | #include 7 | using namespace std; 8 | 9 | #include 10 | using namespace std; 11 | 12 | ClientSocket::ClientSocket() : Socket() 13 | { 14 | } 15 | 16 | ClientSocket::ClientSocket(const string& ip, int port) : Socket(ip, port) 17 | { 18 | m_sockfd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 19 | if (m_sockfd < 0) 20 | { 21 | error("create client socket error: errno=%d errstr=%s", errno, strerror(errno)); 22 | return; 23 | } 24 | Socket::connect(ip, port); 25 | } 26 | 27 | ClientSocket::~ClientSocket() 28 | { 29 | close(); 30 | } 31 | -------------------------------------------------------------------------------- /socket/ClientSocket.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | using namespace std; 5 | 6 | #include "Socket.h" 7 | 8 | namespace yazi { 9 | namespace socket { 10 | 11 | class ClientSocket : public Socket 12 | { 13 | public: 14 | ClientSocket(); 15 | ClientSocket(const string &ip, int port); 16 | virtual ~ClientSocket(); 17 | }; 18 | 19 | }} 20 | -------------------------------------------------------------------------------- /socket/EventPoller.cpp: -------------------------------------------------------------------------------- 1 | #include "EventPoller.h" 2 | 3 | using namespace yazi::socket; 4 | 5 | EventPoller::EventPoller(bool et) : m_epfd(0), m_max_connections(0), m_events(NULL), m_et(et) 6 | { 7 | } 8 | 9 | EventPoller::~EventPoller() 10 | { 11 | if (m_epfd > 0) 12 | { 13 | close(m_epfd); 14 | m_epfd = 0; 15 | } 16 | 17 | if (m_events != NULL) 18 | { 19 | delete[] m_events; 20 | m_events = NULL; 21 | } 22 | } 23 | 24 | void EventPoller::ctrl(int fd, void * ptr, __uint32_t events, int op) 25 | { 26 | struct epoll_event ev; 27 | ev.data.ptr = ptr; 28 | if (m_et) 29 | { 30 | ev.events = events | EPOLLET; 31 | } 32 | else 33 | { 34 | ev.events = events; 35 | } 36 | epoll_ctl(m_epfd, op, fd, &ev); 37 | } 38 | 39 | void EventPoller::create(int max_connections) 40 | { 41 | m_max_connections = max_connections; 42 | m_epfd = epoll_create(max_connections + 1); 43 | if (m_epfd < 0) 44 | { 45 | return; 46 | } 47 | if (m_events != NULL) 48 | { 49 | delete[] m_events; 50 | m_events = NULL; 51 | } 52 | m_events = new epoll_event[max_connections + 1]; 53 | } 54 | 55 | void EventPoller::add(int fd, void * ptr, __uint32_t events) 56 | { 57 | ctrl(fd, ptr, events, EPOLL_CTL_ADD); 58 | } 59 | 60 | void EventPoller::mod(int fd, void * ptr, __uint32_t events) 61 | { 62 | ctrl(fd, ptr, events, EPOLL_CTL_MOD); 63 | } 64 | 65 | void EventPoller::del(int fd, void * ptr, __uint32_t events) 66 | { 67 | ctrl(fd, ptr, events, EPOLL_CTL_DEL); 68 | } 69 | 70 | int EventPoller::wait(int millsecond) 71 | { 72 | return epoll_wait(m_epfd, m_events, m_max_connections + 1, millsecond); 73 | } 74 | -------------------------------------------------------------------------------- /socket/EventPoller.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace yazi { 9 | namespace socket { 10 | 11 | class EventPoller 12 | { 13 | friend class SocketHandler; 14 | 15 | public: 16 | /** 17 | * @brief 构造函数. 18 | * @param et 默认是ET模式 19 | */ 20 | EventPoller(bool et = true); 21 | ~EventPoller(); 22 | 23 | /** 24 | * @brief 生成 epoll句柄. 25 | * @param max_connections epoll服务需要支持的最大连接数 26 | */ 27 | void create(int max_connections); 28 | 29 | /** 30 | * @brief 添加监听句柄. 31 | * @param fd 句柄 32 | * @param ptr 辅助的数据, 可以后续在epoll_event中获取到 33 | * @param event 需要监听的事件EPOLLIN|EPOLLOUT 34 | * 35 | */ 36 | void add(int fd, void * ptr, __uint32_t events); 37 | 38 | /** 39 | * @brief 修改句柄事件. 40 | * @param fd 句柄 41 | * @param ptr 辅助的数据, 可以后续在epoll_event中获取到 42 | * @param event 需要监听的事件EPOLLIN|EPOLLOUT 43 | */ 44 | void mod(int fd, void * ptr, __uint32_t events); 45 | 46 | /** 47 | * @brief 删除句柄事件. 48 | * @param fd 句柄 49 | * @param ptr 辅助的数据, 可以后续在epoll_event中获取到 50 | * @param event 需要监听的事件EPOLLIN|EPOLLOUT 51 | */ 52 | void del(int fd, void * ptr, __uint32_t events); 53 | 54 | /** 55 | * @brief 等待时间. 56 | * @param millsecond 毫秒 57 | * @return int 有事件触发的句柄数 58 | */ 59 | int wait(int millsecond); 60 | 61 | protected: 62 | 63 | /** 64 | * @brief 控制 epoll,将EPOLL设为边缘触发EPOLLET模式 65 | * @param fd 句柄,在create函数时被赋值 66 | * @param ptr 辅助的数据, 可以后续在epoll_event中获取到 67 | * @param events 需要监听的事件 68 | * EPOLLIN 表示对应的文件描述符可以读 69 | * EPOLLOUT 表示对应的文件描述符可以写 70 | * EPOLLPRI 表示对应的文件描述符有紧急的数据可读 71 | * EPOLLERR 表示对应的文件描述符发生错误 72 | * EPOLLHUP 表示对应的文件描述符被挂断 73 | * EPOLLET 表示对应的文件描述符有事件发生 74 | * @param op 控制 epoll 文件描述符上的事件:注册、修改、删除 75 | * EPOLL_CTL_ADD:注册新的fd到epfd中 76 | * EPOLL_CTL_MOD:修改已经注册的fd的监听事件 77 | * EPOLL_CTL_DEL:从 epfd中删除一个fd; 78 | * 79 | */ 80 | void ctrl(int fd, void * ptr, __uint32_t events, int op); 81 | 82 | protected: 83 | 84 | /** 85 | * epoll 86 | */ 87 | int m_epfd; 88 | 89 | /** 90 | * 最大连接数 91 | */ 92 | int m_max_connections; 93 | 94 | /** 95 | * 事件集 96 | */ 97 | struct epoll_event * m_events; 98 | 99 | /** 100 | * 是否是ET模式 101 | */ 102 | bool m_et; 103 | }; 104 | 105 | }} 106 | -------------------------------------------------------------------------------- /socket/ServerSocket.cpp: -------------------------------------------------------------------------------- 1 | #include "ServerSocket.h" 2 | #include "Logger.h" 3 | 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | using namespace yazi::utility; 9 | using namespace yazi::socket; 10 | 11 | ServerSocket::ServerSocket() : Socket() 12 | { 13 | } 14 | 15 | ServerSocket::ServerSocket(const string &ip, int port) : Socket(ip, port) 16 | { 17 | m_sockfd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 18 | if (m_sockfd < 0) 19 | { 20 | error("create server socket error: errno=%d errstr=%s", errno, strerror(errno)); 21 | return; 22 | } 23 | 24 | set_non_blocking(); 25 | set_recv_buffer(10 * 1024); 26 | set_send_buffer(10 * 1024); 27 | set_linger(true, 0); 28 | set_keep_alive(); 29 | set_reuse_addr(); 30 | bind(ip, port); 31 | listen(1024); 32 | } 33 | 34 | ServerSocket::~ServerSocket() 35 | { 36 | close(); 37 | } 38 | -------------------------------------------------------------------------------- /socket/ServerSocket.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | using namespace std; 5 | 6 | #include "Socket.h" 7 | 8 | namespace yazi { 9 | namespace socket { 10 | 11 | class ServerSocket : public Socket 12 | { 13 | public: 14 | ServerSocket(); 15 | ServerSocket(const string &ip, int port); 16 | virtual ~ServerSocket(); 17 | }; 18 | 19 | }} 20 | -------------------------------------------------------------------------------- /socket/Socket.cpp: -------------------------------------------------------------------------------- 1 | #include "Socket.h" 2 | #include "Logger.h" 3 | 4 | using namespace yazi::utility; 5 | using namespace yazi::socket; 6 | 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | Socket::Socket() : m_sockfd(0) 13 | { 14 | } 15 | 16 | Socket::Socket(const string &ip, int port) : m_ip(ip), m_port(port), m_sockfd(0) 17 | { 18 | } 19 | 20 | Socket::~Socket() 21 | { 22 | close(); 23 | } 24 | 25 | bool Socket::bind(const string &ip, int port) 26 | { 27 | struct sockaddr_in sockaddr; 28 | memset(&sockaddr, 0, sizeof(sockaddr)); 29 | sockaddr.sin_family = AF_INET; 30 | if (ip != "") 31 | { 32 | sockaddr.sin_addr.s_addr = inet_addr(ip.c_str()); 33 | } 34 | else 35 | { 36 | sockaddr.sin_addr.s_addr = htonl(INADDR_ANY); 37 | } 38 | sockaddr.sin_port = htons(port); 39 | 40 | if (::bind(m_sockfd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) 41 | { 42 | error("socket bind error: errno=%d errstr=%s", errno, strerror(errno)); 43 | return false; 44 | } 45 | return true; 46 | } 47 | 48 | bool Socket::listen(int backlog) 49 | { 50 | if (::listen(m_sockfd, backlog) < 0) 51 | { 52 | error("socket listen error: errno=%d errstr=%s", errno, strerror(errno)); 53 | return false; 54 | } 55 | return true; 56 | } 57 | 58 | bool Socket::connect(const string &ip, int port) 59 | { 60 | struct sockaddr_in sockaddr; 61 | memset(&sockaddr, 0, sizeof(sockaddr)); 62 | sockaddr.sin_family = AF_INET; 63 | sockaddr.sin_addr.s_addr = inet_addr(ip.c_str()); 64 | sockaddr.sin_port = htons(port); 65 | if (::connect(m_sockfd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) 66 | { 67 | error("socket connect error: errno=%d errstr=%s", errno, strerror(errno)); 68 | return false; 69 | } 70 | return true; 71 | } 72 | 73 | bool Socket::close() 74 | { 75 | if (m_sockfd > 0) 76 | { 77 | ::close(m_sockfd); 78 | m_sockfd = 0; 79 | } 80 | return true; 81 | } 82 | 83 | int Socket::accept() 84 | { 85 | int sockfd = ::accept(m_sockfd, NULL, NULL); 86 | if (sockfd < 0) 87 | { 88 | error("accept call error: errno=%d errstr=%s", errno, strerror(errno)); 89 | sockfd = -1; 90 | } 91 | return sockfd; 92 | } 93 | 94 | int Socket::recv(char * buf, int len) 95 | { 96 | return ::recv(m_sockfd, buf, len, 0); 97 | } 98 | 99 | int Socket::send(const char * buf, int len) 100 | { 101 | return ::send(m_sockfd, buf, len, 0); 102 | } 103 | 104 | bool Socket::set_non_blocking() 105 | { 106 | int flags = fcntl(m_sockfd, F_GETFL, 0); 107 | if (flags < 0) 108 | { 109 | error("Socket::set_non_blocking(F_GETFL, O_NONBLOCK): errno=%d errstr=%s", errno, strerror(errno)); 110 | return false; 111 | } 112 | flags |= O_NONBLOCK; 113 | if (fcntl(m_sockfd, F_SETFL, flags) < 0) 114 | { 115 | error("Socket::set_non_blocking(F_SETFL, O_NONBLOCK): errno=%d errstr=%s", errno, strerror(errno)); 116 | return false; 117 | } 118 | return true; 119 | } 120 | 121 | bool Socket::set_send_buffer(int size) 122 | { 123 | int buff_size = size; 124 | if (setsockopt(m_sockfd, SOL_SOCKET, SO_SNDBUF, &buff_size, sizeof(buff_size)) < 0) 125 | { 126 | error("socket set send buffer error: errno=%d errstr=%s", errno, strerror(errno)); 127 | return false; 128 | } 129 | return true; 130 | } 131 | 132 | bool Socket::set_recv_buffer(int size) 133 | { 134 | int buff_size = size; 135 | if (setsockopt(m_sockfd, SOL_SOCKET, SO_RCVBUF, &buff_size, sizeof(buff_size)) < 0) 136 | { 137 | error("socket set recv buffer error: errno=%d errstr=%s", errno, strerror(errno)); 138 | return false; 139 | } 140 | return true; 141 | } 142 | 143 | bool Socket::set_linger(bool active, int seconds) 144 | { 145 | struct linger l; 146 | memset(&l, 0, sizeof(l)); 147 | 148 | if (active) 149 | l.l_onoff = 1; 150 | else 151 | l.l_onoff = 0; 152 | l.l_linger = seconds; 153 | 154 | if (setsockopt(m_sockfd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0) 155 | { 156 | error("socket set sock linger error: errno=%d errstr=%s", errno, strerror(errno)); 157 | return false; 158 | } 159 | return true; 160 | } 161 | 162 | bool Socket::set_keep_alive() 163 | { 164 | int flag = 1; 165 | if (setsockopt(m_sockfd, SOL_SOCKET, SO_KEEPALIVE, &flag, sizeof(flag)) < 0) 166 | { 167 | error("socket set sock keep alive error: errno=%d errstr=%s", errno, strerror(errno)); 168 | return false; 169 | } 170 | return true; 171 | } 172 | 173 | bool Socket::set_reuse_addr() 174 | { 175 | int flag = 1; 176 | if (setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)) < 0) 177 | { 178 | error("socket set sock reuser addr error: errno=%s errstr=%s", errno, strerror(errno)); 179 | return false; 180 | } 181 | return true; 182 | } 183 | 184 | bool Socket::set_reuse_port() 185 | { 186 | int flag = 1; 187 | if (setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEPORT, &flag, sizeof(flag)) < 0) 188 | { 189 | error("socket set sock reuser port error: errno=%d errstr=%s", errno, strerror(errno)); 190 | return false; 191 | } 192 | return true; 193 | } 194 | -------------------------------------------------------------------------------- /socket/Socket.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | using namespace std; 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | using namespace std; 14 | 15 | namespace yazi { 16 | namespace socket { 17 | 18 | class Socket 19 | { 20 | friend class SocketHandler; 21 | 22 | public: 23 | Socket(); 24 | Socket(const string &ip, int port); 25 | virtual ~Socket(); 26 | 27 | bool bind(const string &ip, int port); 28 | bool listen(int backlog); 29 | bool connect(const string &ip, int port); 30 | bool close(); 31 | 32 | int accept(); 33 | int recv(char * buf, int len); 34 | int send(const char * buf, int len); 35 | 36 | bool set_non_blocking(); 37 | bool set_send_buffer(int size); 38 | bool set_recv_buffer(int size); 39 | bool set_linger(bool active, int seconds); 40 | bool set_keep_alive(); 41 | bool set_reuse_addr(); 42 | bool set_reuse_port(); 43 | 44 | protected: 45 | string m_ip; 46 | int m_port; 47 | int m_sockfd; 48 | }; 49 | 50 | }} 51 | -------------------------------------------------------------------------------- /socket/SocketHandler.cpp: -------------------------------------------------------------------------------- 1 | #include "SocketHandler.h" 2 | 3 | #include "Logger.h" 4 | #include "IniFile.h" 5 | #include "Singleton.h" 6 | using namespace yazi::utility; 7 | 8 | #include "Task.h" 9 | #include "AutoLock.h" 10 | #include "TaskDispatcher.h" 11 | using namespace yazi::thread; 12 | 13 | #include "ServerSocket.h" 14 | using namespace yazi::socket; 15 | 16 | #include "TaskFactory.h" 17 | using namespace yazi::task; 18 | 19 | SocketHandler::SocketHandler() 20 | { 21 | } 22 | 23 | SocketHandler::~SocketHandler() 24 | { 25 | if (m_epoll != NULL) 26 | { 27 | delete m_epoll; 28 | m_epoll = NULL; 29 | } 30 | if (m_server != NULL) 31 | { 32 | delete m_server; 33 | m_server = NULL; 34 | } 35 | } 36 | 37 | void SocketHandler::listen(const string & ip, int port) 38 | { 39 | m_server = new ServerSocket(ip, port); 40 | } 41 | 42 | void SocketHandler::attach(Socket * socket) 43 | { 44 | AutoLock lock(&m_mutex); 45 | m_epoll->add(socket->m_sockfd, (void *)socket, (EPOLLONESHOT | EPOLLIN | EPOLLHUP | EPOLLERR)); 46 | } 47 | 48 | void SocketHandler::detach(Socket * socket) 49 | { 50 | AutoLock lock(&m_mutex); 51 | m_epoll->del(socket->m_sockfd, (void *)socket, (EPOLLONESHOT | EPOLLIN | EPOLLHUP | EPOLLERR)); 52 | } 53 | 54 | void SocketHandler::remove(Socket * socket) 55 | { 56 | socket->close(); 57 | m_sockpool.release(socket); 58 | } 59 | 60 | void SocketHandler::handle(int max_connections, int wait_time) 61 | { 62 | m_epoll = new EventPoller(false); 63 | m_epoll->create(max_connections); 64 | m_epoll->add(m_server->m_sockfd, m_server, (EPOLLIN | EPOLLHUP | EPOLLERR)); 65 | m_sockpool.init(max_connections); 66 | 67 | debug("epoll wait time: %dms", wait_time); 68 | while (true) 69 | { 70 | int num = m_epoll->wait(wait_time); 71 | if (num == 0) 72 | { 73 | // debug("no events"); 74 | continue; 75 | } 76 | for (int i = 0; i < num; i++) 77 | { 78 | if (m_server == static_cast(m_epoll->m_events[i].data.ptr)) 79 | { 80 | debug("socket accept event"); 81 | int soctfd = m_server->accept(); 82 | Socket * socket = m_sockpool.allocate(); 83 | if (socket == NULL) 84 | { 85 | error("socket pool is empty"); 86 | break; 87 | } 88 | socket->m_sockfd = soctfd; 89 | socket->set_non_blocking(); 90 | attach(socket); 91 | } 92 | else 93 | { 94 | Socket * socket = static_cast(m_epoll->m_events[i].data.ptr); 95 | if (m_epoll->m_events[i].events & EPOLLHUP) 96 | { 97 | error("socket %d closed by peer.", socket->m_sockfd); 98 | detach(socket); 99 | remove(socket); 100 | } 101 | else if (m_epoll->m_events[i].events & EPOLLERR) 102 | { 103 | error("socket %d error.", socket->m_sockfd); 104 | detach(socket); 105 | remove(socket); 106 | } 107 | else if (m_epoll->m_events[i].events & EPOLLIN) 108 | { 109 | debug("socket read event"); 110 | detach(socket); 111 | Task * task = TaskFactory::create(socket); 112 | Singleton::instance()->assign(task); 113 | } 114 | } 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /socket/SocketHandler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | using std::list; 5 | 6 | #include 7 | using std::string; 8 | 9 | //#include 10 | //#include 11 | #include "Socket.h" 12 | #include "EventPoller.h" 13 | 14 | #include "ObjectPool.h" 15 | using namespace yazi::utility; 16 | 17 | #include "Mutex.h" 18 | #include "Task.h" 19 | using namespace yazi::thread; 20 | 21 | namespace yazi { 22 | namespace socket { 23 | 24 | class SocketHandler 25 | { 26 | public: 27 | SocketHandler(); 28 | ~SocketHandler(); 29 | 30 | void listen(const string & ip, int port); 31 | void attach(Socket * socket); 32 | void detach(Socket * socket); 33 | void remove(Socket * socket); 34 | void handle(int max_connections, int wait_time); 35 | 36 | private: 37 | EventPoller * m_epoll; 38 | Socket * m_server; 39 | ObjectPool m_sockpool; 40 | Mutex m_mutex; 41 | }; 42 | 43 | }} 44 | -------------------------------------------------------------------------------- /task/EchoTask.cpp: -------------------------------------------------------------------------------- 1 | #include "EchoTask.h" 2 | using namespace yazi::task; 3 | 4 | #include "Logger.h" 5 | #include "Singleton.h" 6 | using namespace yazi::utility; 7 | 8 | #include "SocketHandler.h" 9 | using namespace yazi::socket; 10 | 11 | 12 | EchoTask::EchoTask(Socket * socket) : Task(socket) 13 | { 14 | } 15 | 16 | EchoTask::~EchoTask() 17 | { 18 | } 19 | 20 | void EchoTask::run() 21 | { 22 | debug("echo task run"); 23 | SocketHandler * handler = Singleton::instance(); 24 | 25 | Socket * socket = static_cast(m_data); 26 | char buf[1024]; 27 | memset(buf, 0, 1024); 28 | int len = socket->recv(buf, 1024); 29 | if (len > 0) 30 | { 31 | debug("recv msg len: %d msg data: %s", len, buf); 32 | socket->send(buf, len); 33 | handler->attach(socket); 34 | } 35 | else 36 | { 37 | debug("echo task socket closed by peer"); 38 | handler->remove(socket); 39 | } 40 | } 41 | 42 | void EchoTask::destroy() 43 | { 44 | debug("echo task destroy"); 45 | delete this; 46 | } 47 | -------------------------------------------------------------------------------- /task/EchoTask.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Task.h" 4 | using namespace yazi::thread; 5 | 6 | #include "Socket.h" 7 | using namespace yazi::socket; 8 | 9 | namespace yazi { 10 | namespace task { 11 | 12 | class EchoTask : public Task 13 | { 14 | public: 15 | EchoTask(Socket * socket); 16 | virtual ~EchoTask(); 17 | 18 | virtual void run(); 19 | 20 | virtual void destroy(); 21 | }; 22 | 23 | }} 24 | -------------------------------------------------------------------------------- /task/PingTask.cpp: -------------------------------------------------------------------------------- 1 | #include "PingTask.h" 2 | using namespace yazi::task; 3 | 4 | #include "Logger.h" 5 | #include "Singleton.h" 6 | using namespace yazi::utility; 7 | 8 | #include "SocketHandler.h" 9 | using namespace yazi::socket; 10 | #include 11 | #include 12 | 13 | 14 | PingTask::PingTask(Socket * socket) : Task(socket) 15 | { 16 | } 17 | 18 | PingTask::~PingTask() 19 | { 20 | } 21 | 22 | void PingTask::run() 23 | { 24 | debug("Ping task run"); 25 | SocketHandler * handler = Singleton::instance(); 26 | 27 | Socket * socket = static_cast(m_data); 28 | char buf[8192]; 29 | memset(buf, 0, 8192); 30 | int len = socket->recv(buf, 8192); 31 | if (len > 0) 32 | { 33 | debug("recv msg len: %d", len); 34 | socket->send("+OK\r\n", 5); 35 | handler->attach(socket); 36 | } 37 | else 38 | { 39 | debug("Ping task socket closed by peer"); 40 | handler->remove(socket); 41 | } 42 | } 43 | 44 | void PingTask::destroy() 45 | { 46 | debug("Ping task destroy"); 47 | delete this; 48 | } 49 | -------------------------------------------------------------------------------- /task/PingTask.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Task.h" 4 | using namespace yazi::thread; 5 | 6 | #include "Socket.h" 7 | using namespace yazi::socket; 8 | 9 | namespace yazi { 10 | namespace task { 11 | 12 | class PingTask : public Task 13 | { 14 | public: 15 | PingTask(Socket * socket); 16 | virtual ~PingTask(); 17 | 18 | virtual void run(); 19 | 20 | virtual void destroy(); 21 | }; 22 | 23 | }} 24 | -------------------------------------------------------------------------------- /task/TaskFactory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Socket.h" 4 | using namespace yazi::socket; 5 | 6 | #include "Task.h" 7 | using namespace yazi::thread; 8 | 9 | #include "EchoTask.h" 10 | #include "WorkTask.h" 11 | #include "PingTask.h" 12 | using namespace yazi::task; 13 | 14 | namespace yazi { 15 | namespace task { 16 | 17 | class TaskFactory 18 | { 19 | public: 20 | static Task * create(Socket * socket) 21 | { 22 | return new WorkTask(socket); 23 | // return new EchoTask(socket); 24 | // return new PingTask(socket); 25 | } 26 | }; 27 | 28 | }} -------------------------------------------------------------------------------- /task/WorkTask.cpp: -------------------------------------------------------------------------------- 1 | #include "WorkTask.h" 2 | 3 | #include "Logger.h" 4 | #include "Singleton.h" 5 | using namespace yazi::utility; 6 | 7 | #include "SocketHandler.h" 8 | using namespace yazi::socket; 9 | 10 | #include "Workflow.h" 11 | using namespace yazi::engine; 12 | 13 | using namespace yazi::task; 14 | 15 | #include 16 | using std::ostringstream; 17 | 18 | 19 | WorkTask::WorkTask(Socket * socket) : Task(socket) 20 | { 21 | } 22 | 23 | WorkTask::~WorkTask() 24 | { 25 | } 26 | 27 | void WorkTask::run() 28 | { 29 | debug("work task run"); 30 | SocketHandler * handler = Singleton::instance(); 31 | 32 | Socket * socket = static_cast(m_data); 33 | 34 | MsgHead msg_head; 35 | memset(&msg_head, 0, sizeof(msg_head)); 36 | int len = socket->recv((char *)(&msg_head), sizeof(msg_head)); 37 | if (len == 0) 38 | { 39 | error("socket closed by peer"); 40 | handler->remove(socket); 41 | return; 42 | } 43 | if (len == -1 && errno == EAGAIN) 44 | { 45 | error("socket recv len: %d, error msg: EAGAIN errno: %d", len, errno); 46 | handler->attach(socket); 47 | return; 48 | } 49 | if (len == -1 && errno == EWOULDBLOCK) 50 | { 51 | error("socket recv len: %d, error msg: EWOULDBLOCK errno: %d", len, errno); 52 | handler->attach(socket); 53 | return; 54 | } 55 | if (len == -1 && errno == EINTR) 56 | { 57 | error("socket recv len: %d, error msg: EINTR errno: %d", len, errno); 58 | handler->attach(socket); 59 | return; 60 | } 61 | if (len != sizeof(msg_head)) 62 | { 63 | error("recv msg head error length: %d, errno: %d", len, errno); 64 | handler->remove(socket); 65 | return; 66 | } 67 | info("recv msg head len: %d, flag: %s, cmd: %d, body len: %d", len, msg_head.flag, msg_head.cmd, msg_head.len); 68 | if (strncmp(msg_head.flag, "work", 4) != 0) 69 | { 70 | error("msg head flag error"); 71 | handler->remove(socket); 72 | return; 73 | } 74 | 75 | if (msg_head.len >= uint32_t(recv_buff_size)) 76 | { 77 | error("recv msg body len: %d, large than recv_buff_size: %d", msg_head.len, recv_buff_size); 78 | handler->remove(socket); 79 | return; 80 | } 81 | 82 | char buf[recv_buff_size]; 83 | memset(buf, 0, recv_buff_size); 84 | len = socket->recv(buf, msg_head.len); 85 | if (len == -1 && errno == EAGAIN) 86 | { 87 | error("socket recv len: %d, error msg: EAGAIN errno: %d", len, errno); 88 | handler->remove(socket); 89 | return; 90 | } 91 | if (len == -1 && errno == EWOULDBLOCK) 92 | { 93 | error("socket recv len: %d, error msg: EWOULDBLOCK errno: %d", len, errno); 94 | handler->remove(socket); 95 | return; 96 | } 97 | if (len == -1 && errno == EINTR) 98 | { 99 | error("socket recv len: %d, error msg: EINTR errno: %d", len, errno); 100 | handler->remove(socket); 101 | return; 102 | } 103 | if (len != (int)(msg_head.len)) 104 | { 105 | error("recv msg body error length: %d, body: %s, errno: %d", len, buf, errno); 106 | handler->remove(socket); 107 | return; 108 | } 109 | 110 | info("recv msg body len: %d, msg data: %s", len, buf); 111 | 112 | Workflow * workflow = Singleton::instance(); 113 | 114 | ostringstream os; 115 | os << (int)(msg_head.cmd); 116 | const string work = os.str(); 117 | const string input = buf; 118 | string output; 119 | 120 | workflow->run(work, input, output); 121 | 122 | socket->send(output.c_str(), output.length()); 123 | handler->attach(socket); 124 | } 125 | 126 | void WorkTask::destroy() 127 | { 128 | debug("work job destory"); 129 | delete this; 130 | } 131 | -------------------------------------------------------------------------------- /task/WorkTask.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Task.h" 4 | using namespace yazi::thread; 5 | 6 | #include "Socket.h" 7 | using namespace yazi::socket; 8 | 9 | namespace yazi { 10 | namespace task { 11 | 12 | struct MsgHead { 13 | char flag[8]; 14 | uint32_t cmd; 15 | uint32_t len; 16 | }; 17 | 18 | const uint32_t recv_buff_size = 1024; 19 | 20 | 21 | class WorkTask : public Task 22 | { 23 | public: 24 | WorkTask(Socket * socket); 25 | virtual ~WorkTask(); 26 | 27 | virtual void run(); 28 | virtual void destroy(); 29 | }; 30 | 31 | }} 32 | -------------------------------------------------------------------------------- /thread/AutoLock.cpp: -------------------------------------------------------------------------------- 1 | #include "AutoLock.h" 2 | 3 | using namespace yazi::thread; 4 | 5 | AutoLock::AutoLock(Mutex* mutex) 6 | { 7 | m_mutex = mutex; 8 | m_mutex->lock(); 9 | } 10 | 11 | AutoLock::~AutoLock() 12 | { 13 | m_mutex->unlock(); 14 | } 15 | -------------------------------------------------------------------------------- /thread/AutoLock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Mutex.h" 4 | 5 | namespace yazi { 6 | namespace thread { 7 | 8 | class AutoLock 9 | { 10 | public: 11 | AutoLock(Mutex* mutex); 12 | ~AutoLock(); 13 | 14 | private: 15 | Mutex* m_mutex; 16 | }; 17 | 18 | }} 19 | -------------------------------------------------------------------------------- /thread/Condition.cpp: -------------------------------------------------------------------------------- 1 | #include "Condition.h" 2 | 3 | using namespace yazi::thread; 4 | 5 | Condition::Condition() 6 | { 7 | pthread_cond_init(&m_cond, NULL); 8 | } 9 | 10 | Condition::~Condition() 11 | { 12 | pthread_cond_destroy(&m_cond); 13 | } 14 | 15 | int Condition::wait(Mutex* mutex) 16 | { 17 | return pthread_cond_wait(&m_cond, &(mutex->m_mutex)); 18 | } 19 | 20 | int Condition::signal() 21 | { 22 | return pthread_cond_signal(&m_cond); 23 | } 24 | 25 | int Condition::broadcast() 26 | { 27 | return pthread_cond_broadcast(&m_cond); 28 | } 29 | 30 | 31 | -------------------------------------------------------------------------------- /thread/Condition.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "Mutex.h" 5 | 6 | namespace yazi { 7 | namespace thread { 8 | 9 | class Condition 10 | { 11 | public: 12 | Condition(); 13 | ~Condition(); 14 | 15 | int wait(Mutex* mutex); 16 | int signal(); 17 | int broadcast(); 18 | 19 | protected: 20 | pthread_cond_t m_cond; 21 | //pthread_condattr_t m_attr; 22 | 23 | }; 24 | 25 | }} 26 | -------------------------------------------------------------------------------- /thread/Mutex.cpp: -------------------------------------------------------------------------------- 1 | #include "Mutex.h" 2 | 3 | using namespace yazi::thread; 4 | 5 | Mutex::Mutex() 6 | { 7 | pthread_mutexattr_t attr; 8 | pthread_mutexattr_init(&attr); 9 | pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); 10 | pthread_mutex_init(&m_mutex, &attr); 11 | pthread_mutexattr_destroy(&attr); 12 | } 13 | 14 | Mutex::~Mutex() 15 | { 16 | pthread_mutex_destroy(&m_mutex); 17 | } 18 | 19 | int Mutex::lock() 20 | { 21 | return pthread_mutex_lock(&m_mutex); 22 | } 23 | 24 | int Mutex::try_lock() 25 | { 26 | return pthread_mutex_trylock(&m_mutex); 27 | } 28 | 29 | int Mutex::unlock() 30 | { 31 | return pthread_mutex_unlock(&m_mutex); 32 | } 33 | 34 | 35 | -------------------------------------------------------------------------------- /thread/Mutex.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace yazi { 5 | namespace thread { 6 | 7 | class Mutex 8 | { 9 | friend class Condition; 10 | 11 | public: 12 | Mutex(); 13 | ~Mutex(); 14 | 15 | // lock 16 | int lock(); 17 | 18 | // try to lock 19 | int try_lock(); 20 | 21 | // unlock 22 | int unlock(); 23 | 24 | private: 25 | pthread_mutex_t m_mutex; 26 | }; 27 | 28 | }} 29 | -------------------------------------------------------------------------------- /thread/Task.cpp: -------------------------------------------------------------------------------- 1 | #include "Task.h" 2 | #include "AutoLock.h" 3 | 4 | using namespace yazi::thread; 5 | 6 | Task::Task() : m_data(NULL) 7 | { 8 | } 9 | 10 | Task::Task(void* data) : m_data(data) 11 | { 12 | } 13 | 14 | Task::~Task() 15 | { 16 | } 17 | 18 | void* Task::get_data() 19 | { 20 | AutoLock lock(&m_mutex); 21 | return m_data; 22 | } 23 | 24 | void Task::set_data(void *data) 25 | { 26 | AutoLock lock(&m_mutex); 27 | m_data = data; 28 | } 29 | -------------------------------------------------------------------------------- /thread/Task.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Mutex.h" 3 | 4 | namespace yazi { 5 | namespace thread { 6 | 7 | class Task 8 | { 9 | public: 10 | Task(); 11 | Task(void* data); 12 | virtual ~Task(); 13 | 14 | void* get_data(); 15 | void set_data(void* data); 16 | 17 | virtual void run() = 0; 18 | virtual void destroy() = 0; 19 | 20 | protected: 21 | void* m_data; 22 | Mutex m_mutex; 23 | }; 24 | 25 | }} 26 | -------------------------------------------------------------------------------- /thread/TaskDispatcher.cpp: -------------------------------------------------------------------------------- 1 | #include "TaskDispatcher.h" 2 | #include "Logger.h" 3 | #include "Singleton.h" 4 | 5 | using namespace yazi::utility; 6 | using namespace yazi::thread; 7 | 8 | TaskDispatcher::TaskDispatcher() 9 | { 10 | } 11 | 12 | TaskDispatcher::~TaskDispatcher() 13 | { 14 | } 15 | 16 | void TaskDispatcher::init(int threads) 17 | { 18 | Singleton::instance()->create(threads); 19 | start(); 20 | } 21 | 22 | void TaskDispatcher::assign(Task* task) 23 | { 24 | debug("task dispatcher assign task"); 25 | m_mutex.lock(); 26 | m_tasks.push_back(task); 27 | m_mutex.unlock(); 28 | m_cond.signal(); 29 | } 30 | 31 | void TaskDispatcher::handle(Task* task) 32 | { 33 | debug("task dispatcher handle task"); 34 | ThreadPool * threadpool = Singleton::instance(); 35 | if (threadpool->get_idle_thread_numbers() > 0) 36 | { 37 | threadpool->assign(task); 38 | } 39 | else 40 | { 41 | m_mutex.lock(); 42 | m_tasks.push_front(task); 43 | m_mutex.unlock(); 44 | debug("all threads are busy!"); 45 | } 46 | } 47 | 48 | void TaskDispatcher::run() 49 | { 50 | sigset_t mask; 51 | if (0 != sigfillset(&mask)) 52 | { 53 | error("thread manager sigfillset failed!"); 54 | return; 55 | } 56 | if (0 != pthread_sigmask(SIG_SETMASK, &mask, NULL)) 57 | { 58 | error("thread manager pthread_sigmask failed!"); 59 | return; 60 | } 61 | while (true) 62 | { 63 | //debug("task list: %d", m_actions.size()); 64 | m_mutex.lock(); 65 | while (m_tasks.empty()) 66 | m_cond.wait(&m_mutex); 67 | Task* task = m_tasks.front(); 68 | m_tasks.pop_front(); 69 | m_mutex.unlock(); 70 | handle(task); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /thread/TaskDispatcher.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "Thread.h" 7 | #include "ThreadPool.h" 8 | #include "Task.h" 9 | 10 | 11 | namespace yazi { 12 | namespace thread { 13 | 14 | class TaskDispatcher : public Thread 15 | { 16 | public: 17 | TaskDispatcher(); 18 | ~TaskDispatcher(); 19 | 20 | void init(int threads); 21 | void assign(Task* task); 22 | void handle(Task* task); 23 | virtual void run(); 24 | 25 | protected: 26 | std::list m_tasks; 27 | }; 28 | 29 | }} 30 | -------------------------------------------------------------------------------- /thread/Thread.cpp: -------------------------------------------------------------------------------- 1 | #include "Thread.h" 2 | #include "AutoLock.h" 3 | using namespace yazi::thread; 4 | 5 | Thread::Thread() : m_tid(0), m_task(NULL) 6 | { 7 | } 8 | 9 | Thread::~Thread() 10 | { 11 | } 12 | 13 | void Thread::start() 14 | { 15 | pthread_attr_t attr; 16 | pthread_attr_init(&attr); 17 | pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); 18 | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 19 | pthread_create(&m_tid, &attr, thread_func, (void *)this); 20 | pthread_attr_destroy(&attr); 21 | } 22 | 23 | void Thread::stop() 24 | { 25 | pthread_exit(PTHREAD_CANCELED); 26 | } 27 | 28 | void* Thread::thread_func(void* ptr) 29 | { 30 | Thread* thread = (Thread *)ptr; 31 | thread->run(); 32 | return ptr; 33 | } 34 | 35 | void Thread::set_task(Task* task) 36 | { 37 | m_mutex.lock(); 38 | m_task = task; 39 | m_cond.signal(); 40 | m_mutex.unlock(); 41 | } 42 | 43 | Task* Thread::get_task() 44 | { 45 | AutoLock lock(&m_mutex); 46 | return m_task; 47 | } 48 | -------------------------------------------------------------------------------- /thread/Thread.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "Mutex.h" 5 | #include "Condition.h" 6 | #include "Task.h" 7 | 8 | namespace yazi { 9 | namespace thread { 10 | 11 | class Thread 12 | { 13 | public: 14 | Thread(); 15 | virtual ~Thread(); 16 | 17 | virtual void run() = 0; 18 | 19 | void start(); 20 | void stop(); 21 | 22 | void set_task(Task* task); 23 | Task* get_task(); 24 | 25 | protected: 26 | static void* thread_func(void* ptr); 27 | 28 | protected: 29 | pthread_t m_tid; 30 | Task* m_task; 31 | Mutex m_mutex; 32 | Condition m_cond; 33 | }; 34 | 35 | }} 36 | -------------------------------------------------------------------------------- /thread/ThreadPool.cpp: -------------------------------------------------------------------------------- 1 | #include "ThreadPool.h" 2 | #include "WorkerThread.h" 3 | #include "Logger.h" 4 | 5 | using namespace yazi::utility; 6 | using namespace yazi::thread; 7 | 8 | ThreadPool::ThreadPool() : m_threads(0) 9 | { 10 | } 11 | 12 | ThreadPool::~ThreadPool() 13 | { 14 | } 15 | 16 | void ThreadPool::create(int threads) 17 | { 18 | AutoLock lock(&m_mutex_idle); 19 | m_threads = threads; 20 | for (int i = 0; i < threads; i++) 21 | { 22 | Thread* thread = new WorkerThread(); 23 | debug("create thread %x", thread); 24 | m_list_idle.insert(thread); 25 | thread->start(); 26 | } 27 | } 28 | 29 | Thread* ThreadPool::get_idle_thread() 30 | { 31 | AutoLock lock(&m_mutex_idle); 32 | while (m_list_idle.size() == 0) 33 | m_cond_idle.wait(&m_mutex_idle); 34 | return *m_list_idle.begin(); 35 | } 36 | 37 | void ThreadPool::move_to_idle_list(Thread *thread) 38 | { 39 | m_mutex_idle.lock(); 40 | m_list_idle.insert(thread); 41 | m_cond_idle.signal(); 42 | m_mutex_idle.unlock(); 43 | 44 | m_mutex_busy.lock(); 45 | std::set::iterator it = m_list_busy.find(thread); 46 | if (it != m_list_busy.end()) 47 | m_list_busy.erase(it); 48 | m_cond_busy.signal(); 49 | m_mutex_busy.unlock(); 50 | } 51 | 52 | void ThreadPool::move_to_busy_list(Thread* thread) 53 | { 54 | m_mutex_busy.lock(); 55 | while (m_list_busy.size() == (size_t)(m_threads)) 56 | m_cond_busy.wait(&m_mutex_busy); 57 | m_list_busy.insert(thread); 58 | m_mutex_busy.unlock(); 59 | 60 | m_mutex_idle.lock(); 61 | std::set::iterator it = m_list_idle.find(thread); 62 | if (it != m_list_idle.end()) 63 | m_list_idle.erase(it); 64 | m_mutex_idle.unlock(); 65 | } 66 | 67 | int ThreadPool::get_idle_thread_numbers() 68 | { 69 | AutoLock lock(&m_mutex_idle); 70 | return m_list_idle.size(); 71 | } 72 | 73 | int ThreadPool::get_busy_thread_numbers() 74 | { 75 | AutoLock lock(&m_mutex_busy); 76 | return m_list_busy.size(); 77 | } 78 | 79 | void ThreadPool::assign(Task *task) 80 | { 81 | if (task == NULL) 82 | { 83 | error("assign a null task to thread pool"); 84 | return; 85 | } 86 | debug("assign a new task: %x to thread pool", task); 87 | 88 | Thread* thread = get_idle_thread(); 89 | if (thread != NULL) 90 | { 91 | move_to_busy_list(thread); 92 | thread->set_task(task); 93 | } 94 | else 95 | { 96 | error("thread is null, assign a task failed"); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /thread/ThreadPool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "Thread.h" 4 | #include "Mutex.h" 5 | #include "AutoLock.h" 6 | #include "Condition.h" 7 | #include "Task.h" 8 | 9 | namespace yazi { 10 | namespace thread { 11 | 12 | 13 | class ThreadPool 14 | { 15 | public: 16 | ThreadPool(); 17 | ~ThreadPool(); 18 | 19 | void create(int threads); 20 | 21 | Thread* get_idle_thread(); 22 | 23 | void move_to_idle_list(Thread* thread); 24 | void move_to_busy_list(Thread* thread); 25 | 26 | int get_idle_thread_numbers(); 27 | int get_busy_thread_numbers(); 28 | 29 | void assign(Task* task); 30 | 31 | private: 32 | int m_threads; 33 | 34 | std::set m_list_idle; 35 | std::set m_list_busy; 36 | 37 | Mutex m_mutex_idle; 38 | Mutex m_mutex_busy; 39 | 40 | Condition m_cond_idle; 41 | Condition m_cond_busy; 42 | }; 43 | 44 | }} 45 | -------------------------------------------------------------------------------- /thread/WorkerThread.cpp: -------------------------------------------------------------------------------- 1 | #include "WorkerThread.h" 2 | 3 | #include "Logger.h" 4 | #include "Singleton.h" 5 | using namespace yazi::utility; 6 | 7 | #include "Task.h" 8 | #include "ThreadPool.h" 9 | using namespace yazi::thread; 10 | 11 | WorkerThread::WorkerThread() : Thread() 12 | { 13 | } 14 | 15 | WorkerThread::~WorkerThread() 16 | { 17 | } 18 | 19 | void WorkerThread::cleanup(void* ptr) 20 | { 21 | info("worker thread cleanup handler: %x", ptr); 22 | } 23 | 24 | void WorkerThread::run() 25 | { 26 | sigset_t mask; 27 | if (0 != sigfillset(&mask)) 28 | { 29 | error("worker thread sigfillset faile!"); 30 | } 31 | if (0 != pthread_sigmask(SIG_SETMASK, &mask, NULL)) 32 | { 33 | error("worker thread pthread_sigmask failed"); 34 | } 35 | pthread_cleanup_push(cleanup, this); 36 | 37 | while (true) 38 | { 39 | // start wait for task 40 | m_mutex.lock(); 41 | while (m_task == NULL) 42 | m_cond.wait(&m_mutex); 43 | m_mutex.unlock(); 44 | // end wait for task 45 | 46 | int rc = 0; 47 | int old_state = 0; 48 | rc = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state); 49 | 50 | m_task->run(); 51 | m_task->destroy(); 52 | m_task = NULL; 53 | 54 | Singleton::instance()->move_to_idle_list(this); 55 | 56 | rc = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_state); 57 | pthread_testcancel(); // cancel-point 58 | } 59 | pthread_cleanup_pop(1); 60 | } 61 | -------------------------------------------------------------------------------- /thread/WorkerThread.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "Thread.h" 7 | 8 | namespace yazi { 9 | namespace thread { 10 | 11 | class WorkerThread : public Thread 12 | { 13 | public: 14 | WorkerThread(); 15 | virtual ~WorkerThread(); 16 | 17 | virtual void run(); 18 | 19 | static void cleanup(void* ptr); 20 | }; 21 | 22 | }} 23 | -------------------------------------------------------------------------------- /utility/IniFile.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "IniFile.h" 5 | 6 | using namespace yazi::utility; 7 | 8 | Value::Value() 9 | { 10 | } 11 | 12 | Value::Value(bool value) 13 | { 14 | *this = value; 15 | } 16 | 17 | Value::Value(int value) 18 | { 19 | *this = value; 20 | } 21 | 22 | Value::Value(double value) 23 | { 24 | *this = value; 25 | } 26 | 27 | Value::Value(const string & value) : m_value(value) 28 | { 29 | } 30 | 31 | Value::~Value() 32 | { 33 | } 34 | 35 | Value & Value::operator = (bool value) 36 | { 37 | if (value) 38 | m_value = "true"; 39 | else 40 | m_value = "false"; 41 | return *this; 42 | } 43 | 44 | Value & Value::operator = (int value) 45 | { 46 | ostringstream os; 47 | os << value; 48 | m_value = os.str(); 49 | return *this; 50 | } 51 | 52 | Value & Value::operator = (double value) 53 | { 54 | ostringstream os; 55 | os << value; 56 | m_value = os.str(); 57 | return *this; 58 | } 59 | 60 | Value & Value::operator = (const string & value) 61 | { 62 | m_value = value; 63 | return *this; 64 | } 65 | 66 | Value::operator bool() 67 | { 68 | if (m_value == "true") 69 | return true; 70 | else if (m_value == "false") 71 | return false; 72 | return false; 73 | } 74 | 75 | Value::operator int() 76 | { 77 | return std::atoi(m_value.c_str()); 78 | } 79 | 80 | Value::operator double() 81 | { 82 | return std::atof(m_value.c_str()); 83 | } 84 | 85 | Value::operator string() 86 | { 87 | return m_value; 88 | } 89 | 90 | Value::operator string() const 91 | { 92 | return m_value; 93 | } 94 | 95 | IniFile::IniFile() 96 | { 97 | } 98 | 99 | IniFile::IniFile(const string &filename) 100 | { 101 | load(filename); 102 | } 103 | 104 | IniFile::~IniFile() 105 | { 106 | } 107 | 108 | string IniFile::trim(string s) 109 | { 110 | if (s.empty()) 111 | { 112 | return s; 113 | } 114 | s.erase(0, s.find_first_not_of(" \r\n")); 115 | s.erase(s.find_last_not_of(" \r\n") + 1); 116 | return s; 117 | } 118 | 119 | bool IniFile::load(const string &filename) 120 | { 121 | m_filename = filename; 122 | m_inifile.clear(); 123 | 124 | string name; 125 | string line; 126 | // open the INI file for reading 127 | ifstream fin(filename.c_str()); 128 | if (fin.fail()) 129 | { 130 | printf("loading file failed: %s is not found.\n", m_filename.c_str()); 131 | return false; 132 | } 133 | while (std::getline(fin, line)) 134 | { 135 | line = trim(line); 136 | if ('[' == line[0]) // it is a section 137 | { 138 | int pos = line.find_first_of(']'); 139 | if (-1 != pos) 140 | { 141 | name = trim(line.substr(1, pos - 1)); 142 | m_inifile[name]; 143 | } 144 | } 145 | else if ('#' == line[0]) // it is a comment 146 | { 147 | continue; 148 | } 149 | else // it is the "key=value" line 150 | { 151 | int pos = line.find_first_of('='); 152 | if (pos > 0) 153 | { 154 | //add new key to the last section in the storage 155 | string key = trim(line.substr(0, pos)); 156 | string value = trim(line.substr(pos + 1, line.size() - pos - 1)); 157 | std::map::iterator it = m_inifile.find(name); 158 | if (it == m_inifile.end()) 159 | { 160 | printf("parsing error: section=%s key=%s\n", name.c_str(), key.c_str()); 161 | return false; 162 | } 163 | m_inifile[name][key] = value; 164 | } 165 | } 166 | } 167 | return true; 168 | } 169 | 170 | void IniFile::save(const string &filename) 171 | { 172 | //open the INI file for writing 173 | ofstream fout(filename.c_str()); 174 | std::map::iterator it; 175 | for (it = m_inifile.begin(); it != m_inifile.end(); ++it) 176 | { 177 | //write section line 178 | fout << "[" << it->first << "]" << endl; 179 | for (Section::iterator iter = it->second.begin(); iter != it->second.end(); ++iter) 180 | { 181 | //write "key = value" line 182 | fout << iter->first << " = " << (string)iter->second << endl; 183 | } 184 | fout << endl; 185 | } 186 | } 187 | 188 | void IniFile::show() 189 | { 190 | std::map::iterator it; 191 | for (it = m_inifile.begin(); it != m_inifile.end(); ++it) 192 | { 193 | //write section line 194 | cout << "[" << it->first << "]" << endl; 195 | Section::iterator iter; 196 | for (iter = it->second.begin(); iter != it->second.end(); ++iter) 197 | { 198 | //write "key = value" line 199 | cout << iter->first << " = " << (string)iter->second << endl; 200 | } 201 | cout << endl; 202 | } 203 | } 204 | 205 | void IniFile::clear() 206 | { 207 | m_inifile.clear(); 208 | } 209 | 210 | bool IniFile::has(const string §ion) 211 | { 212 | return (m_inifile.find(section) != m_inifile.end()); 213 | } 214 | 215 | bool IniFile::has(const string §ion, const string& key) 216 | { 217 | std::map::iterator it = m_inifile.find(section); 218 | if (it != m_inifile.end()) 219 | { 220 | return (it->second.find(key) != it->second.end()); 221 | } 222 | return false; 223 | } 224 | 225 | Value & IniFile::get(const string §ion, const string &key) 226 | { 227 | return m_inifile[section][key]; 228 | } 229 | 230 | void IniFile::set(const string §ion, const string &key, bool value) 231 | { 232 | m_inifile[section][key] = value; 233 | } 234 | 235 | void IniFile::set(const string §ion, const string &key, int value) 236 | { 237 | m_inifile[section][key] = value; 238 | } 239 | 240 | void IniFile::set(const string §ion, const string &key, double value) 241 | { 242 | m_inifile[section][key] = value; 243 | } 244 | 245 | void IniFile::set(const string §ion, const string &key, const string &value) 246 | { 247 | m_inifile[section][key] = value; 248 | } 249 | 250 | void IniFile::remove(const string §ion) 251 | { 252 | std::map::iterator it = m_inifile.find(section); 253 | if (it != m_inifile.end()) 254 | m_inifile.erase(it); 255 | } 256 | 257 | void IniFile::remove(const string §ion, const string &key) 258 | { 259 | std::map::iterator it = m_inifile.find(section); 260 | if (it != m_inifile.end()) 261 | { 262 | Section::iterator iter = it->second.find(key); 263 | if (iter != it->second.end()) 264 | it->second.erase(iter); 265 | } 266 | } 267 | 268 | -------------------------------------------------------------------------------- /utility/IniFile.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | #include 9 | using std::ostringstream; 10 | 11 | namespace yazi { 12 | namespace utility { 13 | 14 | class Value 15 | { 16 | public: 17 | Value(); 18 | Value(bool value); 19 | Value(int value); 20 | Value(double value); 21 | Value(const string & value); 22 | ~Value(); 23 | 24 | Value & operator = (bool value); 25 | Value & operator = (int value); 26 | Value & operator = (double value); 27 | Value & operator = (const string & value); 28 | 29 | operator bool(); 30 | operator int(); 31 | operator double(); 32 | operator string(); 33 | operator string() const; 34 | 35 | private: 36 | string m_value; 37 | }; 38 | 39 | class IniFile 40 | { 41 | public: 42 | IniFile(); 43 | IniFile(const string &filename); 44 | ~IniFile(); 45 | 46 | bool load(const string &filename); 47 | void save(const string &filename); 48 | void show(); 49 | void clear(); 50 | 51 | // read values in different formats 52 | Value & get(const string §ion, const string &key); 53 | 54 | // set values in different formats 55 | void set(const string §ion, const string &key, bool value); 56 | void set(const string §ion, const string &key, int value); 57 | void set(const string §ion, const string &key, double value); 58 | void set(const string §ion, const string &key, const string &value); 59 | 60 | bool has(const string §ion); 61 | bool has(const string §ion, const string &key); 62 | 63 | void remove(const string §ion); 64 | void remove(const string §ion, const string &key); 65 | 66 | typedef std::map Section; 67 | Section & operator [] (const string & key) 68 | { 69 | return m_inifile[key]; 70 | } 71 | 72 | private: 73 | string trim(string s); 74 | 75 | private: 76 | string m_filename; 77 | 78 | std::map m_inifile; 79 | }; 80 | 81 | }} 82 | -------------------------------------------------------------------------------- /utility/Logger.cpp: -------------------------------------------------------------------------------- 1 | #include "Logger.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace yazi::utility; 8 | 9 | const char* Logger::s_level[LEVEL_COUNT] = 10 | { 11 | "DEBUG", 12 | "INFO", 13 | "WARN", 14 | "ERROR", 15 | "FATAL" 16 | }; 17 | 18 | Logger *Logger::m_instance = NULL; 19 | 20 | Logger::Logger() : m_max(0), m_len(0), m_level(DEBUG) 21 | { 22 | } 23 | 24 | Logger::~Logger() 25 | { 26 | close(); 27 | } 28 | 29 | Logger* Logger::instance() 30 | { 31 | if (m_instance == NULL) 32 | m_instance = new Logger(); 33 | return m_instance; 34 | } 35 | 36 | void Logger::open(const string &filename) 37 | { 38 | m_filename = filename; 39 | m_fout.open(filename.c_str(), ios::app); 40 | if (m_fout.fail()) 41 | { 42 | throw std::logic_error("open log file failed: " + filename); 43 | } 44 | m_fout.seekp(0, ios::end); 45 | m_len = m_fout.tellp(); 46 | } 47 | 48 | void Logger::close() 49 | { 50 | m_fout.close(); 51 | } 52 | 53 | void Logger::log(Level level, const char* file, int line, const char* format, ...) 54 | { 55 | if (m_level > level) 56 | { 57 | return; 58 | } 59 | 60 | if (m_fout.fail()) 61 | { 62 | throw std::logic_error("open log file failed: " + m_filename); 63 | } 64 | 65 | time_t ticks = time(NULL); 66 | struct tm* ptm = localtime(&ticks); 67 | char timestamp[32]; 68 | memset(timestamp, 0, sizeof(timestamp)); 69 | strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", ptm); 70 | 71 | int len = 0; 72 | const char * fmt = "%s %s %s:%d "; 73 | len = snprintf(NULL, 0, fmt, timestamp, s_level[level], file, line); 74 | if (len > 0) 75 | { 76 | char * buffer = new char[len + 1]; 77 | snprintf(buffer, len + 1, fmt, timestamp, s_level[level], file, line); 78 | buffer[len] = 0; 79 | m_fout << buffer; 80 | delete buffer; 81 | m_len += len; 82 | } 83 | 84 | va_list arg_ptr; 85 | va_start(arg_ptr, format); 86 | len = vsnprintf(NULL, 0, format, arg_ptr); 87 | va_end(arg_ptr); 88 | if (len > 0) 89 | { 90 | char * content = new char[len + 1]; 91 | va_start(arg_ptr, format); 92 | vsnprintf(content, len + 1, format, arg_ptr); 93 | va_end(arg_ptr); 94 | content[len] = 0; 95 | m_fout << content; 96 | delete content; 97 | m_len += len; 98 | } 99 | 100 | m_fout << "\n"; 101 | m_fout.flush(); 102 | 103 | if (m_max > 0 && m_len >= m_max) 104 | { 105 | rotate(); 106 | } 107 | } 108 | 109 | void Logger::max(int bytes) 110 | { 111 | m_max = bytes; 112 | } 113 | 114 | void Logger::level(int level) 115 | { 116 | m_level = level; 117 | } 118 | 119 | void Logger::rotate() 120 | { 121 | close(); 122 | time_t ticks = time(NULL); 123 | struct tm* ptm = localtime(&ticks); 124 | char timestamp[32]; 125 | memset(timestamp, 0, sizeof(timestamp)); 126 | strftime(timestamp, sizeof(timestamp), ".%Y-%m-%d_%H-%M-%S", ptm); 127 | string filename = m_filename + timestamp; 128 | if (rename(m_filename.c_str(), filename.c_str()) != 0) 129 | { 130 | throw std::logic_error("rename log file failed: " + string(strerror(errno))); 131 | } 132 | open(m_filename); 133 | } 134 | 135 | 136 | -------------------------------------------------------------------------------- /utility/Logger.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | namespace yazi { 8 | namespace utility { 9 | 10 | #define debug(format, ...) \ 11 | Logger::instance()->log(Logger::DEBUG, __FILE__, __LINE__, format, ##__VA_ARGS__) 12 | 13 | #define info(format, ...) \ 14 | Logger::instance()->log(Logger::INFO, __FILE__, __LINE__, format, ##__VA_ARGS__) 15 | 16 | #define warn(format, ...) \ 17 | Logger::instance()->log(Logger::WARN, __FILE__, __LINE__, format, ##__VA_ARGS__) 18 | 19 | #define error(format, ...) \ 20 | Logger::instance()->log(Logger::ERROR, __FILE__, __LINE__, format, ##__VA_ARGS__) 21 | 22 | #define fatal(format, ...) \ 23 | Logger::instance()->log(Logger::FATAL, __FILE__, __LINE__, format, ##__VA_ARGS__) 24 | 25 | 26 | class Logger 27 | { 28 | public: 29 | enum Level 30 | { 31 | DEBUG = 0, 32 | INFO, 33 | WARN, 34 | ERROR, 35 | FATAL, 36 | LEVEL_COUNT 37 | }; 38 | 39 | static Logger* instance(); 40 | void open(const string &filename); 41 | void close(); 42 | void log(Level level, const char* file, int line, const char* format, ...); 43 | void max(int bytes); 44 | void level(int level); 45 | 46 | private: 47 | Logger(); 48 | ~Logger(); 49 | void rotate(); 50 | 51 | private: 52 | string m_filename; 53 | ofstream m_fout; 54 | int m_max; 55 | int m_len; 56 | int m_level; 57 | static const char* s_level[LEVEL_COUNT]; 58 | static Logger *m_instance; 59 | }; 60 | 61 | }} 62 | -------------------------------------------------------------------------------- /utility/ObjectPool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "Mutex.h" 5 | #include "AutoLock.h" 6 | 7 | using namespace yazi::thread; 8 | 9 | namespace yazi { 10 | namespace utility { 11 | 12 | template 13 | class ObjectPool 14 | { 15 | public: 16 | ObjectPool(); 17 | ~ObjectPool(); 18 | 19 | void init(int max); 20 | T * allocate(); 21 | void release(T * p); 22 | 23 | private: 24 | std::list m_pool; 25 | Mutex m_mutex; 26 | }; 27 | 28 | template 29 | ObjectPool::ObjectPool() 30 | { 31 | } 32 | 33 | template 34 | ObjectPool::~ObjectPool() 35 | { 36 | AutoLock lock(&m_mutex); 37 | for (typename std::list::iterator it = m_pool.begin(); it != m_pool.end(); it++) 38 | { 39 | if ((*it) != NULL) 40 | { 41 | delete (*it); 42 | } 43 | } 44 | m_pool.clear(); 45 | } 46 | 47 | template 48 | void ObjectPool::init(int max) 49 | { 50 | AutoLock lock(&m_mutex); 51 | for (int i = 0; i < max; i++) 52 | { 53 | T * p = new T(); 54 | m_pool.push_back(p); 55 | } 56 | } 57 | 58 | template 59 | T * ObjectPool::allocate() 60 | { 61 | AutoLock lock(&m_mutex); 62 | if (m_pool.size() == 0) 63 | { 64 | return NULL; 65 | } 66 | T * p = m_pool.front(); 67 | m_pool.pop_front(); 68 | return p; 69 | } 70 | 71 | template 72 | void ObjectPool::release(T * p) 73 | { 74 | AutoLock lock(&m_mutex); 75 | m_pool.push_back(p); 76 | } 77 | 78 | }} 79 | -------------------------------------------------------------------------------- /utility/Singleton.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace yazi { 4 | namespace utility { 5 | 6 | template 7 | class Singleton 8 | { 9 | public: 10 | static T * instance() 11 | { 12 | if (m_instance == NULL) 13 | m_instance = new T(); 14 | return m_instance; 15 | } 16 | 17 | private: 18 | Singleton() {} 19 | Singleton(const Singleton &); 20 | Singleton & operator = (const Singleton &); 21 | ~Singleton() {} 22 | 23 | private: 24 | static T * m_instance; 25 | }; 26 | 27 | template 28 | T * Singleton::m_instance = NULL; 29 | 30 | }} 31 | -------------------------------------------------------------------------------- /utility/System.cpp: -------------------------------------------------------------------------------- 1 | #include "System.h" 2 | using namespace yazi::utility; 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "Logger.h" 11 | #include "IniFile.h" 12 | #include "Singleton.h" 13 | using namespace yazi::utility; 14 | 15 | #include "Workflow.h" 16 | using namespace yazi::engine; 17 | 18 | 19 | System::System() 20 | { 21 | } 22 | 23 | System::~System() 24 | { 25 | } 26 | 27 | void System::init() 28 | { 29 | core_dump(); 30 | 31 | m_root_path = get_root_path(); 32 | 33 | const string & logdir = m_root_path + "/log"; 34 | DIR * dp = opendir(logdir.c_str()); 35 | if (dp == NULL) 36 | { 37 | mkdir(logdir.c_str(), 0755); 38 | } 39 | else 40 | { 41 | closedir(dp); 42 | } 43 | 44 | // init logger 45 | Logger::instance()->open(m_root_path + "/log/main.log"); 46 | 47 | // init inifile 48 | IniFile * ini = Singleton::instance(); 49 | ini->load(get_root_path() + "/config/main.ini"); 50 | 51 | // init workflow 52 | Workflow * workflow = Singleton::instance(); 53 | workflow->load(get_root_path() + "/config/workflow.xml"); 54 | } 55 | 56 | void System::core_dump() 57 | { 58 | // core dump 59 | struct rlimit x; 60 | int ret = getrlimit(RLIMIT_CORE, &x); 61 | x.rlim_cur = x.rlim_max; 62 | ret = setrlimit(RLIMIT_CORE, &x); 63 | 64 | ret = getrlimit(RLIMIT_DATA, &x); 65 | x.rlim_cur = 768000000; 66 | ret = setrlimit(RLIMIT_DATA, &x); 67 | } 68 | 69 | string System::get_root_path() 70 | { 71 | if (m_root_path != "") 72 | { 73 | return m_root_path; 74 | } 75 | char path[1024]; 76 | memset(path, 0, 1024); 77 | int cnt = readlink("/proc/self/exe", path, 1024); 78 | if (cnt < 0 || cnt >= 1024) 79 | { 80 | return ""; 81 | } 82 | for (int i = cnt; i >= 0; --i) 83 | { 84 | if (path[i] == '/') 85 | { 86 | path[i] = '\0'; 87 | break; 88 | } 89 | } 90 | return string(path); 91 | } 92 | -------------------------------------------------------------------------------- /utility/System.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | using namespace std; 5 | 6 | namespace yazi { 7 | namespace utility { 8 | 9 | class System 10 | { 11 | public: 12 | System(); 13 | ~System(); 14 | 15 | void init(); 16 | string get_root_path(); 17 | 18 | private: 19 | void core_dump(); 20 | 21 | private: 22 | string m_root_path; 23 | }; 24 | 25 | }} 26 | -------------------------------------------------------------------------------- /xml/Document.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "Document.h" 7 | using namespace yazi::xml; 8 | 9 | Document::Document() : m_idx(0) 10 | { 11 | } 12 | 13 | Document::~Document() 14 | { 15 | } 16 | 17 | void Document::load_file(const string & filename) 18 | { 19 | std::ifstream in(filename.c_str()); 20 | ostringstream buf; 21 | char ch; 22 | while(in.get(ch)) 23 | { 24 | buf.put(ch); 25 | } 26 | load_string(buf.str()); 27 | } 28 | 29 | void Document::load_string(const string & str) 30 | { 31 | m_str = str; 32 | m_idx = 0; 33 | } 34 | 35 | void Document::skip_white_spaces() 36 | { 37 | while (m_str[m_idx] == ' ' || m_str[m_idx] == '\r' || m_str[m_idx] == '\n' || m_str[m_idx] == '\t') 38 | m_idx++; 39 | } 40 | 41 | Element Document::parse() 42 | { 43 | skip_white_spaces(); 44 | if (m_idx == m_str.size() || m_str[m_idx] == '\0') 45 | { 46 | throw std::logic_error("xml document is empty"); 47 | } 48 | 49 | // parse xml declaration 50 | if (m_str[m_idx + 0] == '<' && 51 | m_str[m_idx + 1] == '?' && 52 | m_str[m_idx + 2] == 'x' && 53 | m_str[m_idx + 3] == 'm' && 54 | m_str[m_idx + 4] == 'l') 55 | { 56 | if (!parse_declaration()) 57 | { 58 | throw std::logic_error("xml declaration is error"); 59 | } 60 | } 61 | 62 | skip_white_spaces(); 63 | 64 | // parse xml comment 65 | if (m_str[m_idx + 0] == '<' && 66 | m_str[m_idx + 1] == '!' && 67 | m_str[m_idx + 2] == '-' && 68 | m_str[m_idx + 3] == '-') 69 | { 70 | if (!parse_comment()) 71 | { 72 | throw std::logic_error("xml comment is error"); 73 | } 74 | } 75 | 76 | skip_white_spaces(); 77 | 78 | Element elem; 79 | string name; 80 | 81 | // parse xml element's 82 | if ((m_str[m_idx + 0] == '<') && (isalpha(m_str[m_idx + 1]) || m_str[m_idx + 1] == '_')) 83 | { 84 | m_idx++; 85 | 86 | // parse elem's name 87 | name = parse_element_name(); 88 | elem.name(name); 89 | 90 | skip_white_spaces(); 91 | 92 | while (m_str[m_idx] != '\0') 93 | { 94 | // empty tag 95 | if (m_str[m_idx + 0] == '/') 96 | { 97 | if (m_str[m_idx + 1] == '>') 98 | { 99 | m_idx += 2; 100 | return elem; 101 | } 102 | else 103 | { 104 | throw std::logic_error("xml empty element is error"); 105 | } 106 | } 107 | else if (m_str[m_idx + 0] == '<') 108 | { 109 | if (m_str[m_idx + 1] == '/') 110 | { 111 | // find the end tag 112 | string end_tag = ""; 113 | size_t pos = m_str.find(end_tag, m_idx); 114 | if (pos == std::string::npos) 115 | { 116 | throw std::logic_error("xml element " + name + " end tag not found"); 117 | } 118 | if (pos == m_idx) 119 | { 120 | m_idx += end_tag.size(); 121 | return elem; 122 | } 123 | } 124 | else if (m_str[m_idx + 0] == '<' && 125 | m_str[m_idx + 1] == '!' && 126 | m_str[m_idx + 2] == '-' && 127 | m_str[m_idx + 3] == '-') 128 | { 129 | // parse xml comment 130 | if (!parse_comment()) 131 | { 132 | throw std::logic_error("xml comment is error"); 133 | } 134 | } 135 | else 136 | { 137 | // parse child element 138 | Element child = parse(); 139 | elem.append(child); 140 | } 141 | } 142 | else if (m_str[m_idx] == '>') 143 | { 144 | m_idx++; 145 | string text = parse_element_text(); 146 | skip_white_spaces(); 147 | if (text != "") 148 | { 149 | elem.text(text); 150 | } 151 | else 152 | { 153 | // parse child element 154 | Element child = parse(); 155 | elem.append(child); 156 | } 157 | } 158 | else 159 | { 160 | // parse elem's attr 161 | string key = parse_element_attr_key(); 162 | 163 | skip_white_spaces(); 164 | 165 | if (m_str[m_idx] != '=') 166 | { 167 | throw std::logic_error("xml element attr is error" + key); 168 | } 169 | m_idx++; 170 | string val = parse_element_attr_val(); 171 | elem.attr(key, val); 172 | } 173 | 174 | skip_white_spaces(); 175 | } 176 | } 177 | return elem; 178 | } 179 | 180 | bool Document::parse_declaration() 181 | { 182 | size_t pos = m_str.find("?>", m_idx); 183 | if (pos == std::string::npos) 184 | { 185 | return false; 186 | } 187 | m_idx = pos + 2; 188 | return true; 189 | } 190 | 191 | bool Document::parse_comment() 192 | { 193 | size_t pos = m_str.find("-->", m_idx); 194 | if (pos == std::string::npos) 195 | { 196 | return false; 197 | } 198 | m_idx = pos + 3; 199 | return true; 200 | } 201 | 202 | string Document::parse_element_name() 203 | { 204 | skip_white_spaces(); 205 | 206 | string out; 207 | if (isalpha(m_str[m_idx]) || (m_str[m_idx] == '_')) 208 | { 209 | out += m_str[m_idx]; 210 | m_idx++; 211 | while ((m_str[m_idx] != '\0') && 212 | (isalnum(m_str[m_idx]) || (m_str[m_idx] == '_') || (m_str[m_idx] == '-') || (m_str[m_idx] == ':'))) 213 | { 214 | out += m_str[m_idx]; 215 | m_idx++; 216 | } 217 | } 218 | return out; 219 | } 220 | 221 | string Document::parse_element_text() 222 | { 223 | skip_white_spaces(); 224 | 225 | string out; 226 | while (m_str[m_idx] != '<') 227 | { 228 | out += m_str[m_idx]; 229 | m_idx++; 230 | } 231 | return out; 232 | } 233 | 234 | string Document::parse_element_attr_key() 235 | { 236 | skip_white_spaces(); 237 | 238 | string out; 239 | if (isalpha(m_str[m_idx]) || (m_str[m_idx] == '_')) 240 | { 241 | out += m_str[m_idx]; 242 | m_idx++; 243 | while (isalnum(m_str[m_idx]) || (m_str[m_idx] == '_') || (m_str[m_idx] == '-') || (m_str[m_idx] == ':')) 244 | { 245 | out += m_str[m_idx]; 246 | m_idx++; 247 | } 248 | } 249 | return out; 250 | } 251 | 252 | string Document::parse_element_attr_val() 253 | { 254 | skip_white_spaces(); 255 | 256 | if (m_str[m_idx] != '"') 257 | { 258 | throw std::logic_error("xml element attr value should be in double quotes"); 259 | } 260 | m_idx++; 261 | 262 | string out; 263 | while (m_str[m_idx] != '"') 264 | { 265 | out += m_str[m_idx]; 266 | m_idx++; 267 | } 268 | 269 | m_idx++; 270 | return out; 271 | } -------------------------------------------------------------------------------- /xml/Document.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | #include "Element.h" 7 | 8 | namespace yazi { 9 | namespace xml { 10 | 11 | class Document 12 | { 13 | public: 14 | Document(); 15 | ~Document(); 16 | 17 | void load_file(const string & filename); 18 | void load_string(const string & str); 19 | void skip_white_spaces(); 20 | Element parse(); 21 | 22 | private: 23 | bool parse_declaration(); 24 | bool parse_comment(); 25 | string parse_element_name(); 26 | string parse_element_text(); 27 | string parse_element_attr_key(); 28 | string parse_element_attr_val(); 29 | 30 | private: 31 | string m_str; 32 | size_t m_idx; 33 | }; 34 | 35 | }} 36 | -------------------------------------------------------------------------------- /xml/Element.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "Element.h" 4 | using namespace yazi::xml; 5 | 6 | Element::Element() 7 | { 8 | } 9 | 10 | Element::Element(const string & name) : m_name(name) 11 | { 12 | } 13 | 14 | Element::Element(const string & name, const string & text) : m_name(name), m_text(text) 15 | { 16 | } 17 | 18 | Element::~Element() 19 | { 20 | } 21 | 22 | const string & Element::name() const 23 | { 24 | return m_name; 25 | } 26 | 27 | const string & Element::text() const 28 | { 29 | return m_text; 30 | } 31 | 32 | void Element::name(const string & name) 33 | { 34 | m_name = name; 35 | } 36 | 37 | void Element::text(const string & text) 38 | { 39 | m_text = text; 40 | } 41 | 42 | string & Element::attr(const string & key) 43 | { 44 | return m_attrs[key]; 45 | } 46 | 47 | void Element::attr(const string & key, const string & value) 48 | { 49 | if (value != "") 50 | { 51 | m_attrs[key] = value; 52 | return; 53 | } 54 | 55 | std::map::iterator it = m_attrs.find(key); 56 | if (it != m_attrs.end()) 57 | { 58 | m_attrs.erase(it); 59 | } 60 | } 61 | 62 | const Element & Element::operator [] (int index) const 63 | { 64 | int size = m_children.size(); 65 | if (index >= 0 && index < size) 66 | { 67 | return m_children.at(index); 68 | } 69 | return null(); 70 | } 71 | 72 | const Element & Element::operator [] (const string & name) const 73 | { 74 | for (Element::const_iterator it = m_children.begin(); it != m_children.end(); it++) 75 | { 76 | if ((*it).name() == name) 77 | { 78 | return (*it); 79 | } 80 | } 81 | return null(); 82 | } 83 | 84 | void Element::append(const Element & child) 85 | { 86 | m_children.push_back(child); 87 | } 88 | 89 | int Element::size() 90 | { 91 | return m_children.size(); 92 | } 93 | 94 | void Element::clear() 95 | { 96 | m_name.clear(); 97 | m_text.clear(); 98 | m_attrs.clear(); 99 | m_children.clear(); 100 | } 101 | 102 | string Element::toString() const 103 | { 104 | if (m_name == "") 105 | { 106 | return ""; 107 | } 108 | std::ostringstream os; 109 | os << "<" << m_name; 110 | for (std::map::const_iterator it = m_attrs.begin(); it != m_attrs.end(); it++) 111 | { 112 | os << " " << it->first << "=\"" << it->second << "\""; 113 | } 114 | os << ">"; 115 | if (m_children.size() > 0) 116 | { 117 | for (std::vector::const_iterator it = m_children.begin(); it != m_children.end(); it++) 118 | { 119 | os << (*it).toString(); 120 | } 121 | } 122 | else 123 | { 124 | os << m_text; 125 | } 126 | os << ""; 127 | return os.str(); 128 | } 129 | 130 | Element const & Element::null() 131 | { 132 | static const Element null; 133 | return null; 134 | } 135 | -------------------------------------------------------------------------------- /xml/Element.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | using std::string; 5 | 6 | #include 7 | #include 8 | 9 | namespace yazi { 10 | namespace xml { 11 | 12 | class Element 13 | { 14 | public: 15 | Element(); 16 | Element(const string & name); 17 | Element(const string & name, const string & text); 18 | ~Element(); 19 | 20 | // get element's name 21 | const string & name() const; 22 | 23 | // set element's name 24 | void name(const string & name); 25 | 26 | // get element's text 27 | const string & text() const; 28 | 29 | // set element's text 30 | void text(const string & text); 31 | 32 | // get element's attr 33 | string & attr(const string & key); 34 | 35 | // set element's attr 36 | void attr(const string & key, const string & value); 37 | 38 | // get child element by index 39 | const Element & operator [] (int index) const; 40 | 41 | // get child element by name 42 | const Element & operator [] (const string & name) const; 43 | 44 | // append child element 45 | void append(const Element & child); 46 | 47 | // get numbers of the child 48 | int size(); 49 | 50 | void clear(); 51 | 52 | string toString() const; 53 | 54 | typedef std::vector::iterator iterator; 55 | typedef std::vector::const_iterator const_iterator; 56 | 57 | iterator begin() 58 | { 59 | return m_children.begin(); 60 | } 61 | 62 | iterator end() 63 | { 64 | return m_children.end(); 65 | } 66 | 67 | const_iterator begin() const 68 | { 69 | return m_children.begin(); 70 | } 71 | 72 | const_iterator end() const 73 | { 74 | return m_children.end(); 75 | } 76 | 77 | static Element const & null(); 78 | 79 | private: 80 | string m_name; 81 | string m_text; 82 | std::vector m_children; 83 | std::map m_attrs; 84 | }; 85 | 86 | }} 87 | --------------------------------------------------------------------------------