├── .gitignore ├── CMakeLists.txt ├── COOKBOOK.md ├── README.md ├── _config.yml ├── app_template ├── app │ ├── CMakeLists.txt.erb │ ├── Gemfile │ ├── Guardfile │ ├── app │ │ ├── assets │ │ │ └── javascripts │ │ │ │ ├── application.js │ │ │ │ └── crails.js │ │ ├── main.cpp │ │ └── routes.cpp │ ├── config │ │ ├── databases.cpp │ │ ├── db.json │ │ ├── logger.cpp │ │ ├── renderers.cpp │ │ ├── request_pipe.cpp │ │ ├── salt.cpp.erb │ │ ├── session_store.cpp.erb │ │ └── ssl.cpp │ ├── public │ │ ├── 404.html │ │ ├── 500.html │ │ └── index.html │ └── spec │ │ └── spec.cpp └── task │ └── tasks │ └── template │ ├── CMakeLists.txt.erb │ └── main.cpp ├── cmake └── Modules │ ├── Findcppnetlib.cmake │ └── Findwebdriverxx.cmake ├── crails.kdev4 ├── crails ├── any_cast.hpp ├── cipher.h ├── controller.hpp ├── cookie_data.hpp ├── database_url.hpp ├── databases.hpp ├── datatree.hpp ├── environment.hpp ├── exception_catcher.hpp ├── file_cache.hpp ├── getenv.hpp ├── http.hpp ├── http_response.hpp ├── http_server.hpp ├── logger.hpp ├── multipart.hpp ├── params.hpp ├── password.hpp ├── platform.hpp ├── program_options.hpp ├── read_file.hpp ├── renderer.hpp ├── request.hpp ├── request_handler.hpp ├── request_handlers │ ├── action.hpp │ └── file.hpp ├── request_parser.hpp ├── router.hpp ├── router_base.hpp ├── safe_ptr.hpp ├── server.hpp ├── session_store.hpp ├── session_store │ ├── cookie_store.hpp │ └── no_session_store.hpp ├── shared_vars.hpp ├── template.hpp ├── tests │ ├── helper.hpp │ ├── request.hpp │ └── runner.hpp ├── thread_id.hpp └── utils │ ├── backtrace.hpp │ ├── flyweight.hpp │ ├── helpers.hpp │ ├── parse_cookie_values.hpp │ ├── regex.hpp │ ├── singleton.hpp │ ├── string.hpp │ └── timer.hpp ├── doc ├── controller.md ├── dynstruct.md ├── getting-started.md ├── models-mongo.md ├── testing.md └── view.md ├── modules ├── attachment │ ├── CMakeLists.txt │ ├── app │ │ └── config │ │ │ └── attachment.cpp │ ├── crails │ │ └── attachment.hpp │ ├── scripts │ │ └── modules │ │ │ └── attachment │ │ │ └── install.rb │ └── src │ │ └── attachment.cpp ├── cache │ ├── CMakeLists.txt │ ├── app │ │ ├── config │ │ │ └── memcached.cpp │ │ └── docker │ │ │ └── base │ │ │ └── compile-libmemcached.sh │ ├── crails │ │ └── memcached.hpp │ ├── scripts │ │ ├── lib │ │ │ └── docker_cache_plugin.rb │ │ └── modules │ │ │ └── cache │ │ │ └── install.rb │ └── src │ │ └── memcached.cpp ├── comet │ ├── CMakeLists.txt │ ├── app │ │ ├── docker │ │ │ └── base │ │ │ │ └── compile-cheerp.sh │ │ └── front │ │ │ ├── CMakeLists.txt.erb │ │ │ ├── application.hpp │ │ │ ├── comet.json │ │ │ ├── main.cpp │ │ │ └── routes.cpp │ ├── crails │ │ ├── archive.hpp │ │ ├── archive_parser.hpp │ │ ├── comet │ │ │ └── mvc │ │ │ │ ├── collection.hpp │ │ │ │ ├── helpers.hpp │ │ │ │ └── model.hpp │ │ ├── raise.hpp │ │ └── renderers │ │ │ └── archive_renderer.hpp │ ├── scripts │ │ ├── guard │ │ │ ├── crails-archive.rb │ │ │ └── templates │ │ │ │ └── archive_renderer.cpp.erb │ │ ├── lib │ │ │ └── docker_comet_plugin.rb │ │ ├── metarecord │ │ │ └── generators │ │ │ │ └── archive_generator.rb │ │ └── modules │ │ │ └── front │ │ │ └── install.rb │ └── src │ │ ├── client │ │ └── mvc │ │ │ └── model.cpp │ │ ├── server │ │ ├── archive_parser.cpp │ │ └── archive_renderer.cpp │ │ └── shared │ │ ├── archive.cpp │ │ └── raise.cpp ├── crud │ ├── CMakeLists.txt │ ├── crails │ │ └── crud │ │ │ ├── belongs_to_controller.hpp │ │ │ ├── controller.hpp │ │ │ └── paginator.hpp │ ├── scripts │ │ └── modules │ │ │ └── crud │ │ │ └── install.rb │ └── src │ │ └── paginator.cpp ├── docker │ ├── CMakeLists.txt │ ├── app │ │ └── docker │ │ │ ├── base │ │ │ ├── Dockerfile │ │ │ ├── boost.sh │ │ │ ├── cppnetlib.sh │ │ │ ├── crails.sh │ │ │ └── package.sh │ │ │ ├── deploy │ │ │ ├── gitignore │ │ │ ├── package.erb │ │ │ └── shell.erb │ └── scripts │ │ ├── lib │ │ └── dockerfile.rb │ │ └── modules │ │ └── docker │ │ ├── add-module.rb │ │ ├── install.rb │ │ └── uninstall.rb ├── html │ ├── CMakeLists.txt │ ├── app │ │ └── lib │ │ │ └── exception.ecpp │ ├── crails │ │ ├── html_template.hpp │ │ └── renderers │ │ │ └── html_renderer.hpp │ ├── scripts │ │ ├── guard │ │ │ ├── crails-ecpp.rb │ │ │ └── templates │ │ │ │ ├── html_renderer.cpp.erb │ │ │ │ └── html_template.cpp.erb │ │ └── modules │ │ │ └── html │ │ │ └── install.rb │ └── src │ │ ├── html_renderer.cpp │ │ └── html_template.cpp ├── image │ ├── CMakeLists.txt │ ├── app │ │ ├── config │ │ │ └── images.cpp │ │ └── docker │ │ │ └── base │ │ │ └── compile-magick++.sh │ ├── crails │ │ └── image.hpp │ ├── scripts │ │ ├── lib │ │ │ └── docker_image_plugin.rb │ │ └── modules │ │ │ └── image │ │ │ └── install.rb │ └── src │ │ └── image.cpp ├── json │ ├── CMakeLists.txt │ ├── app │ │ └── lib │ │ │ └── exception.cjson │ ├── crails │ │ ├── json_template.hpp │ │ └── renderers │ │ │ └── json_renderer.hpp │ ├── scripts │ │ ├── guard │ │ │ ├── crails-cjson.rb │ │ │ └── templates │ │ │ │ ├── json_renderer.cpp.erb │ │ │ │ └── json_template.cpp.erb │ │ └── modules │ │ │ └── json │ │ │ └── install.rb │ └── src │ │ ├── json_renderer.cpp │ │ └── json_template.cpp ├── mail │ ├── CMakeLists.txt │ ├── app │ │ └── config │ │ │ └── mailers.json │ ├── crails │ │ ├── mail_servers.hpp │ │ ├── mailer.hpp │ │ └── smtp.hpp │ ├── scripts │ │ └── modules │ │ │ └── mail │ │ │ └── install.rb │ └── src │ │ ├── mail_servers.cpp │ │ ├── mailer.cpp │ │ └── smtp.cpp ├── metarecord │ ├── CMakeLists.txt │ ├── crails │ │ └── models │ │ │ └── helpers.hpp │ └── scripts │ │ └── modules │ │ └── models │ │ └── install.rb ├── mongodb │ ├── CMakeLists.txt │ ├── app │ │ ├── config │ │ │ ├── db.json │ │ │ └── session_store.cpp │ │ └── docker │ │ │ └── base │ │ │ └── compile-mongo-cxx-driver.sh │ ├── crails │ │ ├── mongodb │ │ │ ├── array.hpp │ │ │ ├── collection.hpp │ │ │ ├── criteria.hpp │ │ │ ├── database.hpp │ │ │ ├── exception.hpp │ │ │ └── model.hpp │ │ └── session_store │ │ │ └── mongodb.hpp │ ├── scripts │ │ ├── guard │ │ │ ├── crails-mongodb-models.rb │ │ │ └── templates │ │ │ │ └── mongodb_model.cpp.erb │ │ ├── lib │ │ │ └── docker_mongodb_plugin.rb │ │ └── modules │ │ │ └── mongodb │ │ │ ├── install-session.rb │ │ │ └── install.rb │ └── src │ │ ├── collection.cpp │ │ ├── criteria.cpp │ │ ├── database.cpp │ │ ├── model.cpp │ │ └── session_store │ │ └── session_mongo_store.cpp ├── odb │ ├── CMakeLists.txt │ ├── app │ │ ├── config │ │ │ ├── odb.cpp │ │ │ └── odb.hpp │ │ ├── docker │ │ │ └── base │ │ │ │ └── compile-odb.sh │ │ └── tasks │ │ │ └── odb_migrate │ │ │ ├── CMakeLists.txt │ │ │ └── main.cpp │ ├── cmake │ │ └── Modules │ │ │ ├── FindODB.cmake │ │ │ └── UseODB.cmake │ ├── crails │ │ └── odb │ │ │ ├── any.hpp │ │ │ ├── connection.hpp │ │ │ ├── controller.hpp │ │ │ ├── database.hpp │ │ │ ├── database_loaders.hpp │ │ │ ├── database_settings.hpp │ │ │ ├── exception.hpp │ │ │ ├── id_type.hpp │ │ │ ├── migrate.hpp │ │ │ ├── migration.hpp │ │ │ ├── model.hpp │ │ │ ├── model │ │ │ ├── base.hpp │ │ │ ├── soft_delete.hpp │ │ │ └── timestamps.hpp │ │ │ ├── traits.hpp │ │ │ ├── traits │ │ │ ├── datatree.hpp │ │ │ └── vector_id.hpp │ │ │ └── transaction.hpp │ ├── scripts │ │ ├── guard │ │ │ └── crails-odb.rb │ │ ├── lib │ │ │ └── docker_odb_plugin.rb │ │ └── modules │ │ │ └── odb │ │ │ └── install.rb │ └── src │ │ ├── connection.cpp │ │ ├── controller.cpp │ │ ├── create_pgsql_database.cpp │ │ ├── database.cpp │ │ ├── database_settings.cpp │ │ ├── migration.cpp │ │ ├── model │ │ ├── base.cpp │ │ ├── soft_delete.cpp │ │ └── timestamps.cpp │ │ └── transaction.cpp ├── proxy │ ├── CMakeLists.txt │ ├── app │ │ └── config │ │ │ └── proxy.json │ ├── crails │ │ └── request_parsers │ │ │ └── proxy.hpp │ ├── scripts │ │ └── modules │ │ │ └── proxy │ │ │ └── install.rb │ └── src │ │ └── proxy.cpp ├── selenium │ ├── CMakeLists.txt │ ├── crails │ │ └── tests │ │ │ ├── background_server.hpp │ │ │ ├── selenium.hpp │ │ │ ├── selenium_helper.hpp │ │ │ └── selenium_server.hpp │ ├── scripts │ │ └── modules │ │ │ └── selenium │ │ │ └── install.rb │ └── src │ │ ├── background_server.cpp │ │ ├── selenium_expectation.cpp │ │ └── selenium_server.cpp ├── sentry │ ├── CMakeLists.txt │ ├── app │ │ └── config │ │ │ └── sentry.cpp │ ├── crails │ │ └── sentry.hpp │ ├── scripts │ │ └── modules │ │ │ └── sentry │ │ │ └── install.rb │ └── src │ │ └── sentry.cpp ├── sidekic │ ├── CMakeLists.txt │ ├── app │ │ ├── config │ │ │ └── sidekic.cpp │ │ └── tasks │ │ │ └── sidekic │ │ │ ├── CMakeLists.txt │ │ │ ├── ctpl.h │ │ │ ├── main.cpp │ │ │ └── sidetasks.cpp │ ├── crails │ │ └── sidekic.hpp │ ├── scripts │ │ └── modules │ │ │ └── sidekic │ │ │ └── install.rb │ └── src │ │ └── sidekic.cpp ├── signin │ ├── CMakeLists.txt │ ├── app │ │ └── config │ │ │ └── signin.cpp │ ├── crails │ │ ├── front │ │ │ └── session.hpp │ │ └── signin │ │ │ ├── auth_controller.hpp │ │ │ ├── model.hpp │ │ │ ├── session.hpp │ │ │ └── session_controller.hpp │ ├── scripts │ │ └── modules │ │ │ └── signin │ │ │ └── install.rb │ └── src │ │ └── model.cpp ├── sync │ ├── CMakeLists.txt │ ├── app │ │ └── config │ │ │ └── sync.cpp │ ├── crails │ │ ├── odb │ │ │ └── sync_connection.hpp │ │ └── sync │ │ │ ├── client.hpp │ │ │ ├── task.hpp │ │ │ └── transaction.hpp │ ├── scripts │ │ └── modules │ │ │ └── sync │ │ │ └── install.rb │ └── src │ │ ├── client.cpp │ │ ├── sync_connection.cpp │ │ ├── task.cpp │ │ └── transaction.cpp └── xmlrpc │ ├── CMakeLists.txt │ ├── crails │ └── xmlrpc │ │ ├── client.hpp │ │ ├── controller.hpp │ │ ├── fault.hpp │ │ ├── struct.hpp │ │ ├── variable.hpp │ │ └── xml_for_method_call.hpp │ ├── scripts │ └── modules │ │ └── xmlrpc │ │ └── install.rb │ └── src │ ├── client.cpp │ ├── controller.cpp │ └── variable.cpp ├── scripts ├── compile.rb ├── crails ├── guard.rb ├── guard │ ├── crails-base-templates.rb │ ├── crails-base.rb │ ├── crails-cmake.rb │ ├── crails-js.rb │ ├── crails-notifier.rb │ └── crails-tests.rb ├── lib │ ├── bundle.rb │ ├── cmakelists.rb │ ├── maincpp.rb │ └── project_model.rb ├── module.rb ├── new.rb ├── server.rb ├── set-env.rb └── task.rb └── src ├── any_cast.cpp ├── body_parser.cpp ├── cgi2params.cpp ├── cipher.cpp ├── controller.cpp ├── controller_basic_authentication.cpp ├── cookie_data.cpp ├── databases.cpp ├── datatree.cpp ├── environment.cpp ├── exception_catcher.cpp ├── file_cache.cpp ├── fileutils.cpp ├── getenv.cpp ├── http.cpp ├── http_response.cpp ├── logger.cpp ├── multipart.cpp ├── params.cpp ├── password.cpp ├── program_options.cpp ├── rand_str.cpp ├── read_file.cpp ├── renderer.cpp ├── request.cpp ├── request_handlers ├── action.cpp └── file.cpp ├── request_parser.cpp ├── request_parsers ├── data_parser.cpp ├── form_parser.cpp ├── json_parser.cpp ├── multipart_parser.cpp └── xml_parser.cpp ├── server.cpp ├── session_cookie_store.cpp ├── session_store └── mongodb │ └── session_store.cpp ├── shared_vars.cpp ├── template.cpp ├── tests ├── helper.cpp ├── main.cpp ├── request.cpp └── runner.cpp └── utils ├── backtrace.cpp ├── parse_cookie_values.cpp ├── string.cpp ├── string_semantics.cpp ├── string_split.cpp └── timer.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | Boots/build 2 | build/ 3 | .*.sw* 4 | .kdev4 5 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-hacker -------------------------------------------------------------------------------- /app_template/app/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'guard' 4 | gem 'guard-compat' 5 | gem 'guard-sass' 6 | 7 | # Uncomment to enable typescript and/or coffee-script support to crailsjs 8 | #gem 'typescript-node' 9 | #gem 'coffee-script' 10 | gem 'uglifier' 11 | -------------------------------------------------------------------------------- /app_template/app/Guardfile: -------------------------------------------------------------------------------- 1 | $: << ENV['CRAILS_SHARED_DIR'] 2 | 3 | group :assets do 4 | guard 'crails-js', input: 'app/assets/javascripts', output: 'public/assets', targets: ['application.js'] 5 | guard 'sass', input: 'app/assets/stylesheets', output: 'public/assets' 6 | end 7 | 8 | group :before_compile do 9 | end 10 | 11 | group :compile do 12 | guard 'crails-cmake' do 13 | watch('CMakeLists.txt') 14 | watch('build/CMakeCache.txt') 15 | watch(%r{^config/.+\.[hc](pp|xx)?$}) 16 | watch(%r{^app/.+\.[hc](pp|xx)?$}) 17 | watch(%r{^lib/.+\.[hc](pp|xx)?$}) 18 | watch(%r{^tasks/.+\.[hc](pp|xx)?$}) 19 | watch(%r{^spec/.+\.[hc](pp|xx)?$}) 20 | end 21 | end 22 | 23 | group :tests do 24 | guard 'crails-tests' do 25 | watch(%r{^build/tests$}) 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /app_template/app/app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | //= require crails.js 2 | -------------------------------------------------------------------------------- /app_template/app/app/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | using namespace Crails; 8 | 9 | int main(int argc, const char **argv) 10 | { 11 | // Initializers 12 | Renderer::initialize(); 13 | if (CookieData::use_encryption) 14 | Cipher::initialize(); 15 | 16 | // Application loop 17 | Server::Launch(argc, argv); 18 | 19 | // Finalizers 20 | Renderer::finalize(); 21 | return (0); 22 | } 23 | -------------------------------------------------------------------------------- /app_template/app/app/routes.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void Crails::Router::initialize(void) 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /app_template/app/config/databases.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace Crails; 4 | 5 | const Databases::Settings Databases::settings = { 6 | { 7 | "production", { 8 | } 9 | }, 10 | 11 | { 12 | "development", { 13 | } 14 | }, 15 | 16 | { 17 | "test", { 18 | } 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /app_template/app/config/db.json: -------------------------------------------------------------------------------- 1 | { 2 | "production": { 3 | "mongodb": { 4 | "host": "127.0.0.1", 5 | "database": "crails_db" 6 | }, 7 | 8 | "mysql": { 9 | "type": "sql", 10 | "host": "127.0.0.1", 11 | "database": "crails_db", 12 | "user": "root" 13 | } 14 | }, 15 | "development": { 16 | "mongodb": { 17 | "host": "127.0.0.1", 18 | "database": "crails_db_dev" 19 | } 20 | }, 21 | "test": { 22 | "mongodb": { 23 | "host": "127.0.0.1", 24 | "database": "crails_db_test" 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app_template/app/config/logger.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace Crails; 4 | 5 | const Logger::Symbol Logger::log_level = Info; 6 | -------------------------------------------------------------------------------- /app_template/app/config/renderers.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace Crails; 4 | 5 | const std::string Renderer::default_format = "text/html"; 6 | 7 | void Renderer::initialize() 8 | { 9 | // Append renderers 10 | } 11 | -------------------------------------------------------------------------------- /app_template/app/config/request_pipe.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace Crails; 6 | 7 | const std::string Server::temporary_path = "/tmp"; 8 | 9 | void Server::initialize_request_pipe() 10 | { 11 | add_request_parser(new RequestDataParser); 12 | add_request_parser(new RequestFormParser); 13 | add_request_parser(new RequestJsonParser); 14 | add_request_parser(new RequestXmlParser); 15 | add_request_parser(new RequestMultipartParser); 16 | 17 | add_request_handler(new FileRequestHandler); 18 | add_request_handler(new ActionRequestHandler); 19 | } 20 | -------------------------------------------------------------------------------- /app_template/app/config/salt.cpp.erb: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace Crails; 4 | using namespace std; 5 | 6 | const bool CookieData::use_encryption = true; 7 | const string CookieData::password = "<%= (0...50).map { (65 + rand(26)).chr }.join %>"; 8 | const string CookieData::salt = "<%= (0...8).map { (65 + rand(61)).chr }.join %>"; 9 | -------------------------------------------------------------------------------- /app_template/app/config/session_store.cpp.erb: -------------------------------------------------------------------------------- 1 | #include .hpp> 2 | #include 3 | 4 | using namespace Crails; 5 | 6 | USE_SESSION_STORE(<%= options[:session_store_class] %>) 7 | 8 | <% if options[:session_store] == 'mongodb' -%> 9 | const std::string MongoStore::SessionStore::collection_name = "session_store"; 10 | const std::string MongoStore::SessionStore::database_name = "mongodb"; 11 | const unsigned int MongoStore::SessionStore::session_expiration = 60 * 30; 12 | <% end -%> 13 | -------------------------------------------------------------------------------- /app_template/app/config/ssl.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace boost; 5 | 6 | namespace Crails 7 | { 8 | std::string get_ssl_password(std::size_t max_length, asio::ssl::context_base::password_purpose purpose) 9 | { 10 | return "your_ssl_password"; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app_template/app/public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Oops ! That's a dead link 4 | 5 | 6 |
7 | This link is dead. 8 |
9 | 10 | 11 | -------------------------------------------------------------------------------- /app_template/app/public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

We're sorry, but something went wrong.

23 |

We've been notified about this issue and we'll take a look at it shortly.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /app_template/app/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Crails Application 4 | 41 | 42 | 43 | 49 |

Welcome to your new Crails Application

50 | 51 | 52 | -------------------------------------------------------------------------------- /app_template/app/spec/spec.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void Crails::Tests::Runner::setup() 4 | { 5 | } 6 | 7 | void Crails::Tests::Runner::shutdown() 8 | { 9 | } 10 | -------------------------------------------------------------------------------- /app_template/task/tasks/template/CMakeLists.txt.erb: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | file(GLOB task_files 4 | *.cpp) 5 | 6 | add_executable(<%= options[:task_name] %> ${task_files}) 7 | 8 | target_link_libraries(<%= options[:task_name] %> ${dependencies}) 9 | 10 | set_target_properties(<%= options[:task_name] %> PROPERTIES OUTPUT_NAME "task") 11 | -------------------------------------------------------------------------------- /app_template/task/tasks/template/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace Crails; 4 | 5 | int main(int argc, char** argv) 6 | { 7 | logger << Logger::Info << "Task example" << Logger::endl; 8 | return 0; 9 | } -------------------------------------------------------------------------------- /cmake/Modules/Findcppnetlib.cmake: -------------------------------------------------------------------------------- 1 | set(CPPNETLIB_PATH) 2 | set(CPPNETLIB_FOUND FALSE) 3 | 4 | find_path(CPPNETLIB_INCLUDE_DIR boost/network/version.hpp HINTS 5 | ${CPPNETLIB_ROOT}/include $ENV{CPPNETLIB_ROOT}/include 6 | ${COMMON_SOURCE_DIR}/cppnetlib ${CMAKE_SOURCE_DIR}/cppnetlib 7 | /usr/local/include 8 | /usr/include) 9 | 10 | if(CPPNETLIB_INCLUDE_DIR) 11 | set(CPPNETLIB_PATH "${CPPNETLIB_INCLUDE_DIR}/..") 12 | endif() 13 | 14 | if(CPPNETLIB_PATH) 15 | set(__libraries cppnetlib-client-connections 16 | cppnetlib-server-parsers 17 | cppnetlib-uri) 18 | 19 | foreach(__library ${__libraries}) 20 | if(TARGET ${__library}) 21 | list(APPEND CPPNETLIB_LIBRARIES ${__library}) 22 | set(CPPNETLIB_FOUND_SUBPROJECT ON) 23 | else() 24 | find_library(${__library} NAMES ${__library} 25 | HINTS ${CPPNETLIB_ROOT} $ENV{CPPNETLIB_ROOT} 26 | PATHS ${CPPNETLIB_PATH}/lib64 ${CPPNETLIB_PATH}/lib) 27 | list(APPEND CPPNETLIB_LIBRARIES ${${__library}}) 28 | endif() 29 | endforeach() 30 | mark_as_advanced(CPPNETLIB_LIBRARIES) 31 | endif() 32 | 33 | 34 | if(NOT cppnetlib_FIND_QUIETLY) 35 | set(_cppnetlib_output 1) 36 | endif() 37 | 38 | include(FindPackageHandleStandardArgs) 39 | 40 | find_package_handle_standard_args(cppnetlib DEFAULT_MSG 41 | CPPNETLIB_LIBRARIES 42 | CPPNETLIB_INCLUDE_DIR) 43 | 44 | if(CPPNETLIB_FOUND) 45 | set(CPPNETLIB_INCLUDE_DIRS ${CPPNETLIB_INCLUDE_DIR}) 46 | if(_cppnetlib_output) 47 | message(STATUS "Found cppnetlib in ${CPPNETLIB_INCLUDE_DIR}:${CPPNETLIB_LIBRARIES}") 48 | endif() 49 | else() 50 | set(CPPNETLIB_INCLUDE_DIRS) 51 | set(CPPNETLIB_INCLUDE_DIR) 52 | set(CPPNETLIB_LIBRARIES) 53 | set(CPPNETLIB_FOUND) 54 | endif() 55 | -------------------------------------------------------------------------------- /cmake/Modules/Findwebdriverxx.cmake: -------------------------------------------------------------------------------- 1 | set(WEBDRIVERXX_PATH) 2 | set(WEBDRIVERXX_FOUND FALSE) 3 | 4 | find_path(WEBDRIVERXX_INCLUDE_DIR webdriverxx/webdriverxx.h HINTS 5 | ${WEBDRIVERXX_ROOT}/include $ENV${WEBDRIVERCXX_ROOT}/include 6 | ${COMMON_SOURCE_DIR}/webdriverxx ${CMAKE_SOURCE_DIR}/webdriverxx 7 | /usr/local/include 8 | /usr/include) 9 | 10 | set(WEBDRIVERXX_LIBRARIES "") 11 | 12 | if(WEBDRIVERXX_INCLUDE_DIR) 13 | set(WEBDRIVERXX_PATH "${WEBDRIVER_INCLUDE_DIR}/..") 14 | endif() 15 | 16 | if(NOT webdriverxx_FIND_QUIETLY) 17 | set(_webdriverxx_output 1) 18 | endif() 19 | 20 | include(FindPackageHandleStandardArgs) 21 | 22 | find_package_handle_standard_args(webdriverxx DEFAULT_MSG 23 | WEBDRIVERXX_INCLUDE_DIR) 24 | 25 | if(WEBDRIVERXX_FOUND) 26 | set(WEBDRIVERXX_INCLUDE_DIRS ${WEBDRIVERCXX_INCLUDE_DIR}) 27 | if(_webdriverxx_output) 28 | message(STATUS "Found webdriverxx in ${WEBDRIVERXX_INCLUDE_DIR}") 29 | endif() 30 | else() 31 | set(WEBDRIVERXX_INCLUDE_DIRS) 32 | set(WEBDRIVERXX_INCLUDE_DIR) 33 | set(WEBDRIVERXX_LIBRARIES) 34 | set(WEBDRIVERXX_FOUND) 35 | endif() 36 | -------------------------------------------------------------------------------- /crails.kdev4: -------------------------------------------------------------------------------- 1 | [Project] 2 | Manager=KDevCMakeManager 3 | Name=crails 4 | -------------------------------------------------------------------------------- /crails/any_cast.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CRAILS_ANY_CAST_HPP 2 | # define CRAILS_ANY_CAST_HPP 3 | 4 | # include 5 | # include 6 | 7 | namespace Crails 8 | { 9 | std::string any_cast(const boost::any& val); 10 | } 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /crails/cookie_data.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COOKIE_DATA_HPP 2 | # define COOKIE_DATA_HPP 3 | 4 | # include 5 | # include "datatree.hpp" 6 | 7 | namespace Crails 8 | { 9 | struct CookieData : public DataTree 10 | { 11 | void unserialize(const std::string&); 12 | std::string serialize(void); 13 | 14 | static const std::string password; 15 | static const std::string salt; 16 | static const bool use_encryption; 17 | }; 18 | } 19 | 20 | #endif -------------------------------------------------------------------------------- /crails/environment.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CRAILS_ENVIRONMENT_HPP 2 | # define CRAILS_ENVIRONMENT_HPP 3 | 4 | # include 5 | 6 | namespace Crails 7 | { 8 | extern std::string environment; 9 | } 10 | 11 | #endif -------------------------------------------------------------------------------- /crails/file_cache.hpp: -------------------------------------------------------------------------------- 1 | #ifndef FILE_CACHE_HPP 2 | # define FILE_CACHE_HPP 3 | 4 | # include 5 | # include 6 | # include 7 | # include 8 | 9 | namespace Crails 10 | { 11 | class FileCache : public Flyweight 12 | { 13 | public: 14 | void lock(void) 15 | { 16 | mutex.lock(); 17 | } 18 | 19 | void unlock(void) 20 | { 21 | mutex.unlock(); 22 | } 23 | 24 | private: 25 | std::shared_ptr create_instance(std::string key); 26 | 27 | std::mutex mutex; 28 | }; 29 | } 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /crails/getenv.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CRAILS_GETENV_HPP 2 | # define CRAILS_GETENV_HPP 3 | 4 | # include 5 | # include 6 | 7 | namespace Crails 8 | { 9 | std::string getenv(const std::string& varname, const std::string& def = ""); 10 | 11 | template 12 | T getenv_as(const std::string& varname, const T value) 13 | { 14 | std::string str_val = getenv(varname); 15 | 16 | if (str_val == "") 17 | return value; 18 | return boost::lexical_cast(str_val); 19 | } 20 | } 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /crails/http.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTTP_HPP 2 | # define HTTP_HPP 3 | 4 | # include 5 | 6 | namespace Crails 7 | { 8 | namespace Http 9 | { 10 | namespace Url 11 | { 12 | std::string Encode(const std::string&); 13 | std::string Decode(const std::string&); 14 | } 15 | } 16 | } 17 | 18 | #endif -------------------------------------------------------------------------------- /crails/http_response.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTTP_RESPONSE 2 | # define HTTP_RESPONSE 3 | 4 | # include "server.hpp" 5 | 6 | namespace Crails 7 | { 8 | class BuildingResponse 9 | { 10 | public: 11 | struct Header 12 | { 13 | Header(const std::string& key, const std::string& value) : key(key), value(value) 14 | {} 15 | 16 | bool operator==(const std::string& comp) const { return (key == comp); } 17 | Header& operator=(const std::string& new_val) { value = new_val; return (*this); } 18 | 19 | std::string key; 20 | std::string value; 21 | }; 22 | 23 | typedef std::list
Headers; 24 | 25 | BuildingResponse(Server::Response response) : response(response) 26 | {} 27 | 28 | void set_response(Server::HttpCode code, const std::string& body); 29 | 30 | void set_status_code(Server::HttpCode code); 31 | void set_headers(const std::string& key, const std::string& value); 32 | void set_body(const char* str, size_t size); 33 | 34 | void bundle(void); 35 | 36 | Server::Response& get_response() { return response; } 37 | const Server::Response& get_response() const { return response; } 38 | 39 | private: 40 | Server::Response response; 41 | Headers headers; 42 | }; 43 | } 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /crails/http_server.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTTP_SERVER_HPP 2 | # define HTTP_SERVER_HPP 3 | 4 | # include 5 | 6 | namespace Crails 7 | { 8 | namespace http = boost::network::http; 9 | 10 | class BuildingResponse; 11 | class Server; 12 | 13 | typedef http::server HttpServer; 14 | 15 | struct ServerTraits 16 | { 17 | typedef HttpServer::connection::status_t HttpCode; 18 | typedef HttpServer::connection HttpCodes; 19 | typedef HttpServer::connection_ptr Response; 20 | }; 21 | } 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /crails/logger.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CRAILS_LOGGER_HPP 2 | # define CRAILS_LOGGER_HPP 3 | 4 | # include 5 | # include 6 | # include 7 | 8 | namespace Crails 9 | { 10 | class Logger 11 | { 12 | public: 13 | enum Symbol 14 | { 15 | Debug = 0, 16 | Info, 17 | Warning, 18 | Error, 19 | endl 20 | }; 21 | 22 | struct Buffer 23 | { 24 | Buffer(); 25 | 26 | std::stringstream stream; 27 | Symbol level; 28 | }; 29 | 30 | Logger(); 31 | 32 | void set_stdout(std::ostream& stream); 33 | void set_stderr(std::ostream& stream); 34 | 35 | Logger& operator<<(Symbol level); 36 | 37 | template 38 | Logger& operator<<(const T item) 39 | { 40 | if (log_level <= buffer.level) 41 | buffer.stream << item; 42 | return *this; 43 | } 44 | 45 | void flush(); 46 | 47 | unsigned char get_log_level() const { return log_level; } 48 | private: 49 | static const Symbol log_level; 50 | static thread_local Buffer buffer; 51 | std::mutex mutex; 52 | std::ostream* stdout; 53 | std::ostream* stderr; 54 | }; 55 | 56 | extern Logger logger; 57 | } 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /crails/multipart.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MULTIPART_HPP 2 | # define MULTIPART_HPP 3 | 4 | # include 5 | # include 6 | 7 | namespace Crails 8 | { 9 | class Params; 10 | 11 | struct MultipartParser 12 | { 13 | void initialize(Params&); 14 | void parse(Params&); 15 | 16 | std::string read_buffer; 17 | unsigned int to_read; 18 | unsigned int total_read; 19 | std::string boundary; 20 | 21 | // Context-linked attributes 22 | short parsed_state; 23 | std::ofstream file; 24 | std::string mimetype; 25 | DataTree content_data; 26 | std::string content_disposition; 27 | }; 28 | } 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /crails/params.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PARAMS_HPP 2 | # define PARAMS_HPP 3 | 4 | # include "datatree.hpp" 5 | # include "session_store.hpp" 6 | # include 7 | 8 | namespace Crails 9 | { 10 | class Server; 11 | struct MultipartParser; 12 | class ActionRequestHandler; 13 | class BodyParser; 14 | class RequestMultipartParser; 15 | 16 | class Params : public DataTree 17 | { 18 | friend class Server; 19 | friend struct MultipartParser; 20 | friend class ActionRequestHandler; 21 | friend class BodyParser; 22 | friend class RequestMultipartParser; 23 | public: 24 | Params(void); 25 | ~Params(void); 26 | 27 | // 28 | struct File 29 | { 30 | bool operator==(const std::string& comp) const { return (key == comp); } 31 | 32 | std::string temporary_path; 33 | std::string name; 34 | std::string key; 35 | std::string mimetype; 36 | }; 37 | 38 | typedef std::list Files; 39 | // 40 | 41 | Data operator[](const std::string& key) { return (DataTree::operator[](key)); } 42 | const File* operator[](const std::string& key) const { return (get_upload(key)); } 43 | #ifdef __llvm__ 44 | Data operator[](const char* key) { return (DataTree::operator[](std::string(key))); } 45 | const File* operator[](const char* key) const { return (get_upload(key)); } 46 | #endif 47 | const File* get_upload(const std::string& key) const; 48 | 49 | Data get_session(void) { return (session->to_data()); } 50 | 51 | private: 52 | std::unique_ptr session; 53 | Files files; 54 | }; 55 | } 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /crails/password.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PASSWORD_HPP 2 | # define PASSWORD_HPP 3 | 4 | # include 5 | # include 6 | 7 | namespace Crails 8 | { 9 | struct Password : public std::string 10 | { 11 | Password(void) 12 | { 13 | } 14 | 15 | Password(const Password& str) : std::string(str.c_str()) 16 | { 17 | } 18 | 19 | Password(const std::string& str) : std::string(md5(str)) 20 | { 21 | } 22 | 23 | Password(const char* str) : std::string(md5(str)) 24 | { 25 | } 26 | 27 | Password& operator=(const std::string& str) 28 | { 29 | std::string::operator=(md5(str)); 30 | return (*this); 31 | } 32 | 33 | Password& operator=(const Password& str) 34 | { 35 | std::string::operator=(str.c_str()); 36 | return (*this); 37 | } 38 | 39 | bool operator==(const Password& str) const 40 | { 41 | return std::string(str.c_str()) == c_str(); 42 | } 43 | 44 | bool operator==(const std::string& str) const 45 | { 46 | return (md5(str) == c_str()); 47 | } 48 | 49 | bool operator==(const char* str) const 50 | { 51 | return (md5(str) == c_str()); 52 | } 53 | 54 | private: 55 | static std::string md5(const std::string& str); 56 | }; 57 | } 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /crails/platform.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CRAILS_PLATFORM_HPP 2 | # define CRAILS_PLATFORM_HPP 3 | 4 | # if defined(__APPLE__) 5 | # define DYNLIB_EXT "dylib" 6 | # elif defined(__linux__) 7 | # define DYNLIB_EXT "so" 8 | # else 9 | # define DYNLIB_EXT "dll" 10 | # endif 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /crails/program_options.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PROGRAM_OPTIONS_HPP 2 | # define PROGRAM_OPTIONS_HPP 3 | 4 | # include 5 | # include 6 | 7 | namespace Crails 8 | { 9 | class ProgramOptions 10 | { 11 | typedef boost::network::http::server_options ServerOptions; 12 | public: 13 | ProgramOptions(int argc, const char** argv); 14 | 15 | HttpServer::options get_server_options(Crails::Server&) const; 16 | 17 | template 18 | T get_value(const std::string& option_name, const T& default_value) const 19 | { 20 | if (vm.count(option_name)) 21 | return vm[option_name].as(); 22 | return default_value; 23 | } 24 | 25 | private: 26 | void initialize_interface(HttpServer::options&) const; 27 | void initialize_thread_pool(HttpServer::options&) const; 28 | void initialize_ssl_context(HttpServer::options&) const; 29 | void initialize_pid_file(HttpServer::options&) const; 30 | 31 | boost::program_options::variables_map vm; 32 | }; 33 | } 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /crails/read_file.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CRAILS_READ_FILE_HPP 2 | # define CRAILS_READ_FILE_HPP 3 | 4 | # include 5 | 6 | namespace Crails 7 | { 8 | bool read_file(const std::string& filepath, std::string& out); 9 | } 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /crails/request.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CRAILS_REQUEST_HPP 2 | # define CRAILS_REQUEST_HPP 3 | 4 | # include "server.hpp" 5 | # include "params.hpp" 6 | 7 | namespace Crails 8 | { 9 | class Request 10 | { 11 | public: 12 | Request(const Server* server, const HttpServer::request&, Server::Response response); 13 | ~Request(); 14 | 15 | const Server& server; 16 | const HttpServer::request request; 17 | int request_id; 18 | Params params; 19 | BuildingResponse out; 20 | Utils::Timer timer; 21 | ExceptionCatcher::Context exception_context; 22 | 23 | void operator()(); 24 | 25 | void run_parser(Server::RequestParsers::const_iterator, std::function); 26 | void run_handler(Server::RequestHandlers::const_iterator, std::function); 27 | 28 | void on_parsed(bool parsed); 29 | void on_handled(bool handled); 30 | void on_finished(); 31 | 32 | void add_reference(); 33 | void remove_reference(); 34 | 35 | private: 36 | unsigned short reference_count; 37 | }; 38 | } 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /crails/request_handler.hpp: -------------------------------------------------------------------------------- 1 | #ifndef REQUEST_HANDLER_HPP 2 | # define REQUEST_HANDLER_HPP 3 | 4 | # include "http_server.hpp" 5 | 6 | namespace Crails 7 | { 8 | class RequestHandler 9 | { 10 | public: 11 | RequestHandler(const std::string& name) : name(name) {} 12 | virtual ~RequestHandler() {} 13 | 14 | const std::string& get_name(void) const { return name; } 15 | 16 | virtual void operator()(const HttpServer::request& request, BuildingResponse& response, Params& params, std::function callback) = 0; 17 | 18 | private: 19 | const std::string name; 20 | }; 21 | } 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /crails/request_handlers/action.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ACTION_REQUEST_HANDLER_HPP 2 | # define ACTION_REQUEST_HANDLER_HPP 3 | 4 | # include "../server.hpp" 5 | 6 | namespace Crails 7 | { 8 | class ActionRequestHandler : public RequestHandler 9 | { 10 | public: 11 | ActionRequestHandler(void) : RequestHandler("action") {} 12 | 13 | void operator()(const HttpServer::request& request, BuildingResponse& out, Params& params, std::function callback); 14 | private: 15 | }; 16 | } 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /crails/request_handlers/file.hpp: -------------------------------------------------------------------------------- 1 | #ifndef FILE_REQUEST_HANDLER_HPP 2 | # define FILE_REQUEST_HANDLER_HPP 3 | 4 | # include "../server.hpp" 5 | 6 | namespace Crails 7 | { 8 | class FileRequestHandler : public RequestHandler 9 | { 10 | friend class Server; 11 | public: 12 | FileRequestHandler() : RequestHandler("file"), file_cache(Crails::Server::get_file_cache()) 13 | { 14 | #ifdef SERVER_DEBUG 15 | cache_enabled = false; 16 | #else 17 | cache_enabled = true; 18 | #endif 19 | } 20 | 21 | void operator()(const HttpServer::request& request, BuildingResponse& response, Params& params, std::function callback); 22 | 23 | void set_cache_enabled(bool enable) { cache_enabled = enable; } 24 | bool is_cache_enabled(void) const { return cache_enabled; } 25 | 26 | protected: 27 | virtual void set_headers_for_file(BuildingResponse& response, const std::string& fullpath) {} 28 | 29 | private: 30 | bool send_file(const std::string& path, BuildingResponse& response, Server::HttpCode code, unsigned int first_bit = 0); 31 | bool if_not_modified(Params&, BuildingResponse&, const std::string& path); 32 | 33 | bool cache_enabled; 34 | FileCache& file_cache; 35 | }; 36 | } 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /crails/safe_ptr.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SMART_POINTER 2 | # define SMART_POINTER 3 | 4 | # include 5 | # include 6 | 7 | struct NullPointerException : public boost_ext::exception 8 | { 9 | public: 10 | const char* what() const throw() 11 | { 12 | return ("A null pointer has been dereferenced."); 13 | } 14 | }; 15 | 16 | template 17 | class safe_ptr : public std::shared_ptr 18 | { 19 | public: 20 | safe_ptr() 21 | { 22 | } 23 | 24 | safe_ptr(T* ptr) : std::shared_ptr(ptr) 25 | { 26 | } 27 | 28 | template 29 | safe_ptr(CPY& cpy) : std::shared_ptr(cpy) 30 | { 31 | } 32 | 33 | safe_ptr& operator=(const std::shared_ptr& cpy) 34 | { 35 | std::shared_ptr::operator=(cpy); 36 | return *this; 37 | } 38 | 39 | T* operator->() const 40 | { 41 | if (this->get() == 0) 42 | throw NullPointerException(); 43 | return (this->get()); 44 | } 45 | 46 | T& operator*(void) const 47 | { 48 | if (this->get() == 0) 49 | throw NullPointerException(); 50 | return (*this->get()); 51 | } 52 | }; 53 | 54 | # define SP(T) ::safe_ptr 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /crails/session_store.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SESSION_STORE_HPP 2 | # define SESSION_STORE_HPP 3 | 4 | # include "crails/cookie_data.hpp" 5 | # include "crails/http_response.hpp" 6 | 7 | # define USE_SESSION_STORE(classname) \ 8 | std::unique_ptr SessionStore::Factory(void) \ 9 | { \ 10 | return (std::unique_ptr(new classname ())); \ 11 | } 12 | 13 | namespace Crails 14 | { 15 | class SessionStore 16 | { 17 | public: 18 | virtual ~SessionStore() {} 19 | static std::unique_ptr Factory(void); 20 | 21 | virtual void load(Data request_headers) = 0; 22 | virtual void finalize(BuildingResponse& response) = 0; 23 | virtual Data to_data(void) = 0; 24 | }; 25 | } 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /crails/session_store/cookie_store.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COOKIE_STORE_HPP 2 | # define COOKIE_STORE_HPP 3 | 4 | # include "crails/cookie_data.hpp" 5 | # include "crails/http_response.hpp" 6 | # include "crails/session_store.hpp" 7 | 8 | namespace Crails 9 | { 10 | class CookieStore : public SessionStore 11 | { 12 | public: 13 | void load(Data request_headers); 14 | void finalize(BuildingResponse& response); 15 | Data to_data(void); 16 | const Data to_data(void) const; 17 | 18 | private: 19 | CookieData cookies; 20 | }; 21 | } 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /crails/session_store/no_session_store.hpp: -------------------------------------------------------------------------------- 1 | #ifndef NO_SESSION_STORE 2 | # define NO_SESSION_STORE 3 | 4 | # include 5 | # include 6 | 7 | namespace Crails 8 | { 9 | class NoSessionStore : public SessionStore 10 | { 11 | public: 12 | void load(Data) {} 13 | void finalize(BuildingResponse&) {} 14 | Data to_data(void) { return stub.to_data(); } 15 | private: 16 | DataTree stub; 17 | }; 18 | } 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /crails/shared_vars.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SHARED_VARS_HPP 2 | # define SHARED_VARS_HPP 3 | 4 | # include 5 | # include 6 | # include 7 | # include "utils/backtrace.hpp" 8 | 9 | namespace Crails 10 | { 11 | typedef std::map SharedVars; 12 | 13 | void output_shared_vars(const SharedVars&); 14 | 15 | template 16 | T cast(const SharedVars& vars, const std::string& name) 17 | { 18 | boost::any var; 19 | 20 | try 21 | { 22 | var = vars.at(name); 23 | 24 | return boost::any_cast(var); 25 | } 26 | catch (std::out_of_range& e) 27 | { 28 | std::string message = "cannot find shared variable `" + name + '`'; 29 | 30 | throw boost_ext::out_of_range(message.c_str()); 31 | } 32 | catch (boost::bad_any_cast& e) 33 | { 34 | throw boost_ext::runtime_error("could not cast `" + name + "` from " + var.type().name() + " to " + typeid(T).name()); 35 | } 36 | } 37 | 38 | template 39 | T cast(const SharedVars& vars, const std::string& name, T default_value) 40 | { 41 | if (vars.find(name) != vars.end()) 42 | return cast(vars, name); 43 | return default_value; 44 | } 45 | } 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /crails/template.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TEMPLATE_HPP 2 | # define TEMPLATE_HPP 3 | 4 | # include "renderer.hpp" 5 | 6 | namespace Crails 7 | { 8 | class Template 9 | { 10 | public: 11 | Template(const Renderer* renderer, SharedVars& vars) : renderer(renderer), vars(vars) 12 | {} 13 | 14 | std::string partial(const std::string& view, SharedVars vars = {}); 15 | private: 16 | const Renderer* renderer; 17 | protected: 18 | SharedVars& vars; 19 | }; 20 | } 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /crails/tests/request.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CRAILS_TESTS_REQUEST_HPP 2 | # define CRAILS_TESTS_REQUEST_HPP 3 | 4 | # include "../router.hpp" 5 | # include "../params.hpp" 6 | 7 | # define EXPECT_STATUS(request, status) \ 8 | EXPECT(request.response["status"].as(), ==, status) 9 | 10 | namespace Crails 11 | { 12 | namespace Tests 13 | { 14 | class Request 15 | { 16 | struct RouterNotInitialized : public std::exception 17 | { 18 | const char* what() const throw() { return "Router not initialized"; } 19 | }; 20 | 21 | struct RouteNotFound : public std::exception 22 | { 23 | RouteNotFound(const std::string& route) : message("Route not found: " + route) {} 24 | const char* what() const throw() { return message.c_str(); } 25 | const std::string message; 26 | }; 27 | 28 | public: 29 | Request(const std::string& method, const std::string& uri); 30 | 31 | void run(); 32 | 33 | Params params; 34 | DataTree response; 35 | private: 36 | }; 37 | } 38 | } 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /crails/tests/runner.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CRAILS_TESTS_RUNNER_HPP 2 | # define CRAILS_TESTS_RUNNER_HPP 3 | 4 | # include "helper.hpp" 5 | # include 6 | 7 | namespace Crails 8 | { 9 | namespace Tests 10 | { 11 | struct Runner 12 | { 13 | void setup(); 14 | void shutdown(); 15 | bool execute(); 16 | 17 | private: 18 | std::list > helpers; 19 | }; 20 | } 21 | } 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /crails/thread_id.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CRAILS_THREAD_ID_HPP 2 | # define CRAILS_THREAD_ID_HPP 3 | 4 | # include 5 | 6 | struct ThreadId 7 | { 8 | public: 9 | ThreadId() 10 | { 11 | static std::atomic value(0); 12 | 13 | id = ++value; 14 | } 15 | 16 | operator unsigned long() const { return id; } 17 | 18 | private: 19 | unsigned long id; 20 | }; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /crails/utils/flyweight.hpp: -------------------------------------------------------------------------------- 1 | #ifndef FLYWEIGHT_HPP 2 | # define FLYWEIGHT_HPP 3 | 4 | # include 5 | # include 6 | # include 7 | # include 8 | 9 | template 10 | class Flyweight 11 | { 12 | struct Instance 13 | { 14 | bool operator==(KEY_TYPE comp) const { return key == comp; } 15 | bool should_garbage_collect() const { return ptr == nullptr || ptr.use_count() == 1; } 16 | 17 | KEY_TYPE key; 18 | std::shared_ptr ptr; 19 | }; 20 | 21 | typedef std::list Instances; 22 | 23 | public: 24 | virtual std::shared_ptr create_instance(KEY_TYPE key) = 0; 25 | 26 | std::shared_ptr require(KEY_TYPE key) 27 | { 28 | auto iterator = std::find(instances.begin(), instances.end(), key); 29 | 30 | if (iterator == instances.end()) 31 | { 32 | Instance instance; 33 | 34 | instance.key = key; 35 | instance.ptr = create_instance(key); 36 | instances.push_back(instance); 37 | return instance.ptr; 38 | } 39 | return iterator->ptr; 40 | } 41 | 42 | bool contains(KEY_TYPE key) 43 | { 44 | auto iterator = std::find(instances.begin(), instances.end(), key); 45 | 46 | return iterator != instances.end(); 47 | } 48 | 49 | void garbage_collect(void) 50 | { 51 | auto it = instances.begin(); 52 | 53 | while (it != instances.end()) 54 | { 55 | if (it->should_garbage_collect()) 56 | it = instances.erase(it); 57 | else 58 | ++it; 59 | } 60 | } 61 | 62 | private: 63 | Instances instances; 64 | }; 65 | 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /crails/utils/helpers.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HELPERS_HPP 2 | # define HELPERS_HPP 3 | 4 | # define ref_attr_getter(type, attr) \ 5 | const type& get_##attr(void) const { return (attr); } \ 6 | type& get_##attr(void) { return (attr); } \ 7 | 8 | # define ref_attr_setter(type, attr) \ 9 | void set_##attr(const type& attr) { this->attr = attr; } 10 | 11 | # define ref_attr_accessor(type, name, attr) ref_attr_getter(type, attr) ref_attr_setter(type, attr) 12 | 13 | # define const_attr_getter(type, attr) \ 14 | const type get_##attr(void) const { return (attr); } 15 | 16 | # define attr_getter(type, attr) \ 17 | type get_##attr(void) const { return (attr); } 18 | 19 | # define attr_setter(type, attr) \ 20 | void set_##attr(const type attr) { this->attr = attr; } 21 | 22 | # define attr_accessor(type, attr) attr_getter(type, attr) attr_setter(type, attr) 23 | 24 | # define const_attr_accessor(type, attr) \ 25 | const_attr_getter(type, attr) \ 26 | attr_setter(type, attr) 27 | 28 | # include 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /crails/utils/parse_cookie_values.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PARSE_COOKIE_VALUES_HPP 2 | # define PARSE_COOKIE_VALUES_HPP 3 | 4 | # include 5 | # include 6 | 7 | namespace Crails 8 | { 9 | void parse_cookie_values(const std::string& str, std::function callback); 10 | } 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /crails/utils/regex.hpp: -------------------------------------------------------------------------------- 1 | #ifndef REGEX_HPP 2 | # define REGEX_HPP 3 | 4 | # include 5 | # include 6 | 7 | class Regex 8 | { 9 | public: 10 | struct Exception : public std::exception 11 | { 12 | Exception(int retval) : regex_error(retval) {} 13 | 14 | int regex_error; 15 | }; 16 | 17 | Regex(void) : has_pattern(false) {} 18 | 19 | Regex(const std::string& pattern, int flags = 0) : has_pattern(false) 20 | { 21 | SetPattern(pattern, flags); 22 | } 23 | 24 | Regex(const Regex& cpy) : has_pattern(false) 25 | { 26 | if (cpy.has_pattern) 27 | SetPattern(cpy.pattern, cpy.flags); 28 | } 29 | 30 | ~Regex(void) 31 | { 32 | Free(); 33 | } 34 | 35 | void SetPattern(const std::string& pattern, int flags = 0); 36 | int Match(const std::string& subject, regmatch_t matches[], size_t max_matches, int eflags = 0) const; 37 | int Match(const std::string& subject, int eflags = 0) const; 38 | 39 | private: 40 | void Free(void); 41 | 42 | regex_t regex; 43 | bool has_pattern; 44 | std::string pattern; 45 | int flags; 46 | }; 47 | 48 | #endif -------------------------------------------------------------------------------- /crails/utils/singleton.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SINGLETON_HPP 2 | # define SINGLETON_HPP 3 | 4 | # include "backtrace.hpp" 5 | 6 | # define SINGLETON(type) \ 7 | public:\ 8 | typedef Singleton singleton; \ 9 | private:\ 10 | friend class Singleton; 11 | 12 | template 13 | class Singleton 14 | { 15 | public: 16 | static void Initialize(Args... args) 17 | { 18 | if (!(ptr)) 19 | ptr = new TYPE(args...); 20 | else 21 | throw boost_ext::runtime_error("Was already initialized"); 22 | } 23 | 24 | static void Finalize(void) 25 | { 26 | if (ptr) 27 | { 28 | delete ptr; 29 | ptr = 0; 30 | } 31 | } 32 | 33 | static TYPE* Get(void) { return (ptr); } 34 | 35 | private: 36 | static TYPE* ptr; 37 | static int val; 38 | }; 39 | 40 | template TYPE* Singleton::ptr = 0; 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /crails/utils/string.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CRAILS_STRING_HPP 2 | # define CRAILS_STRING_HPP 3 | 4 | # include 5 | # include 6 | 7 | namespace Crails 8 | { 9 | std::string generate_random_string(const std::string& charset, unsigned short length); 10 | 11 | std::string underscore(const std::string&); 12 | std::string humanize(const std::string&); 13 | std::string strip(const std::string&); 14 | std::list split(const std::string& str, char separator = ' ', bool count_repetitions = false); 15 | std::string singularize(const std::string&); 16 | std::string pluralize(const std::string&); 17 | 18 | std::string base64_encode(unsigned char const* str, unsigned int len); 19 | std::string base64_encode(const std::string& str_to_encode); 20 | std::string base64_decode(const std::string& str_to_decode); 21 | } 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /crails/utils/timer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TIMER_HPP 2 | # define TIMER_HPP 3 | 4 | # ifdef _WIN32 5 | # include 6 | # else 7 | # include 8 | # endif 9 | 10 | namespace Utils 11 | { 12 | /*! \class Timer 13 | * \brief That's a timer. It counts time. */ 14 | class Timer 15 | { 16 | public: 17 | Timer() { Restart(); } 18 | 19 | float GetElapsedMilliseconds(void) const; 20 | float GetElapsedSeconds(void) const { return (GetElapsedMilliseconds() / 1000); } 21 | void Restart(void); 22 | private: 23 | # ifdef _WIN32 24 | clock_t _lastTime; 25 | # else 26 | struct timeval _lastTime; 27 | # endif 28 | }; 29 | } 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /doc/dynstruct.md: -------------------------------------------------------------------------------- 1 | ### DynStruct 2 | DynStruct is an object that serializes/unserializes data in text mode. Any node from the root of the DynStruct can 3 | contain a value or a set of other nodes. Unexisting nodes are created on the fly and garbage collected when they go 4 | out of scope. This means you can do stuff like this: 5 | 6 | ```C++ 7 | DynStruct render_data; 8 | 9 | if ((render_data["whatever"]["something"]["something_else"].Nil())) 10 | std::cout << "This node does not exist" << std::endl; 11 | ``` 12 | 13 | If you set a value on an unexisting node, it will be saved along with all the unexisting parent nodes. This means that 14 | this is a correct use of the DynStruct: 15 | 16 | ```C++ 17 | render_data["nonexisting-node"]["a key"] = "A value"; 18 | ``` 19 | 20 | They also support any type that is suppoted by std streams. So this s correct as well: 21 | 22 | ```C++ 23 | render_data["key"] = 42.f; 24 | ``` 25 | It also automatically cast to the expected type: 26 | 27 | ```C++ 28 | unsigned int number = render_data["key"]; 29 | ``` 30 | 31 | Use the "value" method to explicitely get the value as a `std::string`: 32 | 33 | ```C++ 34 | std::string mystring = render_data["key"].Value(); 35 | ``` 36 | -------------------------------------------------------------------------------- /modules/attachment/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(crails-attachment) 4 | 5 | include_directories(.) 6 | 7 | file(GLOB crails_attachment src/*.cpp) 8 | file(GLOB headers_crails_attachment crails/*.hpp) 9 | file(GLOB scripts_crails_attachment scripts/modules/attachment/*.rb) 10 | file(GLOB_RECURSE attachmant_app_template app/*) 11 | 12 | add_library(crails-attachment${crails-suffix} SHARED ${crails_attachment}) 13 | install(FILES ${headers_crails_attachment} DESTINATION include/crails) 14 | install(FILES ${attachment_app_template} DESTINATION share/crails/app_template/attachment) 15 | install(FILES ${scripts_crails_attachment} DESTINATION share/crails/scripts/modules/attachment) 16 | install(TARGETS crails-attachment${crails-suffix} LIBRARY DESTINATION lib) 17 | 18 | -------------------------------------------------------------------------------- /modules/attachment/app/config/attachment.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | using namespace Crails; 5 | 6 | const string Attachment::default_store_path = "crails-attachment"; 7 | -------------------------------------------------------------------------------- /modules/attachment/crails/attachment.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CRAILS_ATTACHMENT_HPP 2 | # define CRAILS_ATTACHMENT_HPP 3 | 4 | # include 5 | # include 6 | 7 | namespace Crails 8 | { 9 | class Attachment : public std::string 10 | { 11 | public: 12 | Attachment() 13 | { 14 | } 15 | 16 | Attachment(const std::string& uid); 17 | 18 | const std::string& get_extension() const { return extension; } 19 | const std::string& get_mimetype() const { return mimetype; } 20 | std::string get_path() const; 21 | 22 | void use_uploaded_file(const Crails::Params::File* file); 23 | 24 | virtual void cleanup_files(); 25 | 26 | virtual std::string get_default_store_path() const 27 | { 28 | return Attachment::default_store_path; 29 | } 30 | 31 | protected: 32 | std::string get_filepath() const; 33 | std::string get_filename() const; 34 | void generate_uid(); 35 | 36 | const static std::string default_store_path; 37 | std::string extension, mimetype; 38 | }; 39 | } 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /modules/attachment/scripts/modules/attachment/install.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | $: << "#{ENV['CRAILS_SHARED_DIR']}/scripts/lib" 4 | 5 | require 'project_model' 6 | require 'cmakelists' 7 | require 'maincpp' 8 | 9 | project = ProjectModel.new 10 | base_directory = Dir.pwd 11 | source = ENV['CRAILS_SHARED_DIR'] + '/app_template/attachment' 12 | 13 | project.base_directory source, base_directory do 14 | project.directory :config do 15 | project.file 'attachment.cpp' 16 | end 17 | end 18 | 19 | cmake = CMakeLists.new 20 | cmake.add_crails_module 'attachment' 21 | cmake.write 22 | 23 | -------------------------------------------------------------------------------- /modules/cache/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(crails-cache) 4 | 5 | file(GLOB crails_cache src/memcached.cpp) 6 | file(GLOB headers_crails_cache crails/memcached.hpp) 7 | file(GLOB crails_cache_templates app/config/memcached.cpp) 8 | file(GLOB crails_cache_scripts scripts/modules/cache/*.rb) 9 | file(GLOB lib_scripts scripts/lib/*.rb) 10 | file(GLOB_RECURSE cache_app_template app/*) 11 | 12 | add_library(crails-cache${crails-suffix} SHARED ${crails_cache}) 13 | 14 | install(FILES ${headers_crails_cache} DESTINATION include/crails) 15 | install(FILES ${crails_cache_templates} DESTINATION share/crails/app_template/cache) 16 | install(FILES ${crails_cache_scripts} DESTINATION share/crails/scripts/modules/cache) 17 | install(FILES ${lib_scripts} DESTINATION share/crails/scripts/lib) 18 | install(FILES ${cache_app_template} DESTINATION share/crails/app_template/cache) 19 | install(TARGETS crails-cache${crails-suffix} LIBRARY DESTINATION lib) 20 | -------------------------------------------------------------------------------- /modules/cache/app/config/memcached.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | const std::string Cache::config = "--SERVER=memcached"; 4 | -------------------------------------------------------------------------------- /modules/cache/app/docker/base/compile-libmemcached.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -ex 2 | 3 | libmemcached_version="1.0.18" 4 | 5 | wget "https://launchpad.net/libmemcached/1.0/1.0.18/+download/libmemcached-${libmemcached_version}.tar.gz" 6 | tar -xzvf libmemcached-${libmemcached_version}.tar.gz 7 | cd libmemcached-${libmemcached_version} 8 | ./configure 9 | make && make install 10 | -------------------------------------------------------------------------------- /modules/cache/scripts/lib/docker_cache_plugin.rb: -------------------------------------------------------------------------------- 1 | class CrailsDocker < CrailsDockerBase 2 | def crails_compile_files 3 | ["compile-libmemcache.sh"] 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /modules/cache/scripts/modules/cache/install.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | $: << "#{ENV['CRAILS_SHARED_DIR']}/scripts/lib" 4 | 5 | require 'project_model' 6 | require 'cmakelists' 7 | 8 | project = ProjectModel.new 9 | base_directory = Dir.pwd 10 | source = ENV['CRAILS_SHARED_DIR'] + '/app_template/cache' 11 | 12 | project.base_directory source, base_directory do 13 | project.directory :config do 14 | project.file 'memcached.cpp' 15 | end 16 | end 17 | 18 | cmake = CMakeLists.new 19 | cmake.add_crails_module 'cache' 20 | cmake.write 21 | -------------------------------------------------------------------------------- /modules/cache/src/memcached.cpp: -------------------------------------------------------------------------------- 1 | #include "../crails/memcached.hpp" 2 | 3 | using namespace Crails; 4 | 5 | Cache::Cache() : memc(0) 6 | { 7 | } 8 | 9 | Cache::~Cache() 10 | { 11 | if (memc) 12 | memcached_free(memc); 13 | } 14 | 15 | void Cache::ensure_initialization() 16 | { 17 | if (memc == 0) 18 | memc = memcached(config.c_str(), config.size()); 19 | } 20 | 21 | void Cache::discard(const std::string& key) 22 | { 23 | instance.ensure_initialization(); 24 | if (instance.memc) 25 | memcached_delete(instance.memc, key.c_str(), key.size(), 0); 26 | } 27 | 28 | namespace Crails 29 | { 30 | template<> 31 | void Cache::serialize(std::string source, const char** buffer, size_t& size) 32 | { 33 | *buffer = source.c_str(); 34 | size = source.size(); 35 | } 36 | 37 | template<> 38 | std::string Cache::unserialize(const char* buffer, size_t size) 39 | { 40 | std::string result; 41 | 42 | return result.assign(buffer, size); 43 | } 44 | } -------------------------------------------------------------------------------- /modules/comet/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(crails-front) 4 | 5 | include_directories(.) 6 | 7 | file(GLOB_RECURSE crails_server_src src/shared/*.cpp src/server/*.cpp) 8 | file(GLOB_RECURSE crails_client_src src/shared/*.cpp src/client/*.cpp 9 | ../../src/utils/string_semantics.cpp 10 | ../../src/utils/string_split.cpp) 11 | file(GLOB guard_front_plugins scripts/guard/*.rb) 12 | file(GLOB metarecord_generators scripts/metarecord/generators/*.rb) 13 | file(GLOB scripts_front_templates scripts/guard/templates/*.erb) 14 | file(GLOB scripts_front_module scripts/modules/front/*.rb) 15 | file(GLOB lib_scripts scripts/lib/*.rb) 16 | file(GLOB_RECURSE docker_template app/docker/*) 17 | file(GLOB_RECURSE front_templates app/front/*) 18 | 19 | add_library(crails-front${crails-suffix} SHARED ${crails_server_src}) 20 | 21 | install(DIRECTORY crails DESTINATION include) 22 | install(FILES ${crails_client_src} DESTINATION share/crails/app_template/front) 23 | install(FILES ${scripts_front_templates} DESTINATION share/crails/guard/templates) 24 | install(FILES ${scripts_front_module} DESTINATION share/crails/scripts/modules/front) 25 | install(FILES ${lib_scripts} DESTINATION share/crails/scripts/lib) 26 | install(FILES ${guard_front_plugins} DESTINATION share/crails/guard) 27 | install(FILES ${metarecord_generators} DESTINATION share/crails/metarecord/generators) 28 | install(FILES ${docker_template} DESTINATION share/crails/app_template/docker) 29 | install(FILES ${front_templates} DESTINATION share/crails/app_template/front) 30 | install(TARGETS crails-front${crails-suffix} LIBRARY DESTINATION lib) 31 | -------------------------------------------------------------------------------- /modules/comet/app/front/CMakeLists.txt.erb: -------------------------------------------------------------------------------- 1 | # -DCMAKE_TOOLCHAIN_FILE "$CHEERP_PATH/share/cmake/Modules/CheerpToolchain.cmake" 2 | cmake_minimum_required(VERSION 3.0) 3 | 4 | project(<%= project_name %>-frontend) 5 | option(DEVELOPER_MODE "enable debugging tools" ON) 6 | 7 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-unknown-pragmas -pedantic") 8 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__CHEERP_CLIENT__ -D__COMET_CLIENT__") 9 | 10 | include_directories(include /usr/local/include ../../lib/comet ../..) 11 | 12 | if(DEVELOPER_MODE) 13 | set(CMAKE_BUILD_TYPE "Debug") 14 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -cheerp-sourcemap=application.js.map -cheerp-sourcemap-standalone") 15 | else() 16 | set(CMAKE_BUILD_TYPE "Release") 17 | #set(CMAKE_CXX_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -cheerp-preexecute") 18 | endif() 19 | 20 | file(GLOB_RECURSE comet_files 21 | *.cpp 22 | ../../lib/app/data/shared/*.cpp 23 | ../../lib/comet/*.cpp) 24 | 25 | file(GLOB_RECURSE crails_comet_files 26 | /usr/local/share/crails/front/*.cpp) 27 | 28 | add_executable(application ${crails_comet_files} ${comet_files}) 29 | -------------------------------------------------------------------------------- /modules/comet/app/front/application.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MY_APPLICATION_HPP 2 | # define MY_APPLICATION_HPP 3 | 4 | # include 5 | 6 | class Application 7 | { 8 | Application() {} 9 | Application(const Application&) = delete; 10 | void operator=(const Application&) = delete; 11 | 12 | public: 13 | static Application& get() 14 | { 15 | static Application instance; 16 | return instance; 17 | } 18 | 19 | static void start() 20 | { 21 | auto& self = get(); 22 | 23 | self.router.start(); 24 | } 25 | 26 | Comet::Router router; 27 | }; 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /modules/comet/app/front/comet.json: -------------------------------------------------------------------------------- 1 | { 2 | "elements": [ 3 | ] 4 | } 5 | -------------------------------------------------------------------------------- /modules/comet/app/front/main.cpp: -------------------------------------------------------------------------------- 1 | #include "application.hpp" 2 | 3 | void webMain() 4 | { 5 | Application::start(); 6 | } 7 | -------------------------------------------------------------------------------- /modules/comet/app/front/routes.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "controllers/application_controller.hpp" 3 | 4 | using namespace Comet; 5 | 6 | void Router::initialize() 7 | { 8 | match_route("/?", ApplicationController, home); 9 | } 10 | -------------------------------------------------------------------------------- /modules/comet/crails/archive_parser.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ARCHIVE_PARSER_HPP 2 | # define ARCHIVE_PARSER_HPP 3 | 4 | # include 5 | 6 | namespace Crails 7 | { 8 | class RequestArchiveParser : public BodyParser 9 | { 10 | public: 11 | void operator()(const HttpServer::request& request, BuildingResponse& out, Params& params, std::function callback); 12 | void body_received(const HttpServer::request&, BuildingResponse&, Params& params, const std::string& body); 13 | }; 14 | } 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /modules/comet/crails/comet/mvc/collection.hpp: -------------------------------------------------------------------------------- 1 | #ifndef FRONTEND_COLLECTION_HPP 2 | # define FRONTEND_COLLECTION_HPP 3 | 4 | # include 5 | # include 6 | 7 | namespace Comet 8 | { 9 | template 10 | class ArchiveCollection : public Collection 11 | { 12 | public: 13 | virtual std::string get_mimetype() const 14 | { 15 | return Archive::mimetype; 16 | } 17 | 18 | protected: 19 | virtual void parse(const std::string& str) 20 | { 21 | IArchive archive; 22 | unsigned long size; 23 | 24 | archive.set_data(str); 25 | archive & size; 26 | for (unsigned long i = 0 ; i < size ; ++i) 27 | { 28 | auto ptr = std::make_shared(); 29 | ptr->serialize(archive); 30 | Collection::models.emplace(ptr->get_id(), ptr); 31 | } 32 | } 33 | }; 34 | } 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /modules/comet/crails/comet/mvc/helpers.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CRAILS_FRONT_MVC_HELPERS_HPP 2 | # define CRAILS_FRONT_MVC_HELPERS_HPP 3 | 4 | # define CRAILS_FRONT_HELPERS 5 | # define ODB_COMPILER 6 | # include 7 | 8 | template 9 | bool update_id_list( 10 | std::vector& model_list, 11 | Data model_ids) 12 | { 13 | auto ids = my_unique >(model_ids); 14 | 15 | for (auto it = model_list.begin() ; it != model_list.end() ;) 16 | { 17 | auto exists_in_new_list = find(ids.begin(), ids.end(), *it); 18 | 19 | if (exists_in_new_list == ids.end()) 20 | it = model_list.erase(it); 21 | else 22 | { 23 | ids.erase(exists_in_new_list); 24 | it++; 25 | } 26 | } 27 | 28 | for (ODB::id_type id : ids) 29 | model_list.push_back(id); 30 | return true; 31 | } 32 | 33 | template 34 | bool update_id_list( 35 | std::list >& model_list, 36 | Data model_ids) 37 | { 38 | auto ids = model_ids.to_vector(); 39 | { 40 | auto it = model_list.begin(); 41 | 42 | while (it != model_list.end()) 43 | { 44 | std::shared_ptr model(*it); 45 | auto exists_in_new_list(find(ids.begin(), ids.end(), model->get_id())); 46 | 47 | if (exists_in_new_list == ids.end()) 48 | it = model_list.erase(it); 49 | else 50 | { 51 | ids.erase(exists_in_new_list); 52 | it++; 53 | } 54 | } 55 | } 56 | 57 | for (ODB::id_type id : ids) 58 | { 59 | auto model = std::make_shared(); 60 | 61 | model->set_id(id); 62 | #ifdef COMET_MODELS_AUTOFETCH 63 | model->fetch(); 64 | #endif 65 | model_list.push_back(model); 66 | } 67 | return true; 68 | } 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /modules/comet/crails/comet/mvc/model.hpp: -------------------------------------------------------------------------------- 1 | #ifndef FRONTEND_MODEL_HPP 2 | # define FRONTEND_MODEL_HPP 3 | 4 | # include 5 | # include 6 | 7 | # define add_model_property(type, name) \ 8 | Crails::Signal name##_changed; \ 9 | type get_##name() const { return name; } \ 10 | void set_##name(type val) \ 11 | { \ 12 | bool is_different = name != val; \ 13 | name = val; \ 14 | if (is_different) \ 15 | { \ 16 | changed.trigger(); \ 17 | name##_changed.trigger(val); \ 18 | } \ 19 | } 20 | 21 | # define add_model_ref_property(type, name) \ 22 | Crails::Signal name##_changed; \ 23 | const type& get_##name() const { return name; } \ 24 | void set_##name(const type& val) \ 25 | { \ 26 | bool is_different = name != val; \ 27 | name = val; \ 28 | if (is_different) \ 29 | { \ 30 | changed.trigger(); \ 31 | name##_changed.trigger(name); \ 32 | } \ 33 | } 34 | 35 | namespace Comet 36 | { 37 | class ArchiveModel : public Model 38 | { 39 | public: 40 | virtual void serialize(OArchive&) = 0; 41 | virtual void serialize(IArchive&) = 0; 42 | void parse(const std::string& str); 43 | protected: 44 | std::string get_payload(); 45 | std::string get_content_type() const; 46 | }; 47 | } 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /modules/comet/crails/raise.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CRAILS_RAISE_HPP 2 | # define CRAILS_RAISE_HPP 3 | 4 | # include 5 | # ifdef __COMET_CLIENT__ 6 | # define boost_ext std 7 | # endif 8 | 9 | namespace Crails 10 | { 11 | void raise(const std::exception& e); 12 | } 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /modules/comet/crails/renderers/archive_renderer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CRAILS_ARCHIVE_RENDERER_HPP 2 | # define CRAILS_ARCHIVE_RENDERER_HPP 3 | 4 | # include 5 | 6 | namespace Crails 7 | { 8 | class ArchiveRenderer : public Renderer 9 | { 10 | public: 11 | ArchiveRenderer(); 12 | 13 | bool can_render(const std::string& accept_header, const std::string& view) const; 14 | void render_template(const std::string& view, Data params, Data response, SharedVars& vars) const; 15 | }; 16 | } 17 | 18 | #endif 19 | 20 | -------------------------------------------------------------------------------- /modules/comet/scripts/guard/crails-archive.rb: -------------------------------------------------------------------------------- 1 | require 'guard/crails-base-templates' 2 | require 'guard/crails-notifier' 3 | 4 | module ::Guard 5 | class CrailsArchive < CrailsTemplatePlugin 6 | def initialize arg 7 | super arg 8 | @base_path = "app/views/" 9 | @template_type = "archive" 10 | @extension = "arch.cpp" 11 | end 12 | 13 | def compile_archive filename 14 | end 15 | end 16 | end 17 | 18 | -------------------------------------------------------------------------------- /modules/comet/scripts/guard/templates/archive_renderer.cpp.erb: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace Crails; 4 | using namespace std; 5 | 6 | <% templates.each do |template| -%> 7 | string <%= template[:function] %>(const Renderer*, SharedVars&); 8 | <% end -%> 9 | 10 | ArchiveRenderer::ArchiveRenderer() 11 | { 12 | <% templates.each do |template| -%> 13 | templates.insert( 14 | pair(<%= template[:name].inspect %>, <%= template[:function] %>) 15 | ); 16 | <% end -%> 17 | } 18 | -------------------------------------------------------------------------------- /modules/comet/scripts/lib/docker_comet_plugin.rb: -------------------------------------------------------------------------------- 1 | class CrailsDocker < CrailsDockerBase 2 | def crails_compile_files 3 | ["compile-cheerp.sh"] 4 | end 5 | 6 | def system_dependencies 7 | ["libxml2-dev", "libz-dev"] 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /modules/comet/src/client/mvc/model.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace Comet; 4 | 5 | std::string ArchiveModel::get_payload() 6 | { 7 | OArchive archive; 8 | 9 | serialize(archive); 10 | return archive.as_string(); 11 | } 12 | 13 | void ArchiveModel::parse(const std::string& str) 14 | { 15 | IArchive archive; 16 | 17 | archive.set_data(str); 18 | serialize(archive); 19 | } 20 | 21 | std::string ArchiveModel::get_content_type() const 22 | { 23 | return Archive::mimetype; 24 | } 25 | -------------------------------------------------------------------------------- /modules/comet/src/server/archive_parser.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "crails/server.hpp" 4 | #include "crails/params.hpp" 5 | #include "crails/logger.hpp" 6 | #include "crails/utils/regex.hpp" 7 | 8 | using namespace std; 9 | using namespace Crails; 10 | 11 | void RequestArchiveParser::operator()(const HttpServer::request& request, BuildingResponse& out, Params& params, function callback) 12 | { 13 | static const regex is_form(Archive::mimetype, regex_constants::extended); 14 | 15 | if (params["method"].defaults_to("GET") != "GET" && content_type_matches(params, is_form)) 16 | { 17 | wait_for_body(request, out, params, [callback]() 18 | { 19 | callback(RequestParser::Stop); 20 | }); 21 | } 22 | else 23 | callback(RequestParser::Continue); 24 | } 25 | 26 | void RequestArchiveParser::body_received(const HttpServer::request& request, BuildingResponse&, Params& params, const string& body) 27 | { 28 | if (body.size() > 0) 29 | params["archive_data"] = body; 30 | } 31 | -------------------------------------------------------------------------------- /modules/comet/src/server/archive_renderer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace Crails; 5 | 6 | bool ArchiveRenderer::can_render(const std::string& accept_header, const std::string& view) const 7 | { 8 | if (accept_header.find(Archive::mimetype) != std::string::npos) 9 | return templates.find(view) != templates.end(); 10 | return false; 11 | } 12 | 13 | void ArchiveRenderer::render_template(const std::string& view, Data params, Data response, SharedVars& vars) const 14 | { 15 | auto tpl = templates.find(view); 16 | std::string body = (*tpl).second(this, vars); 17 | 18 | response["headers"]["Content-Type"] = Archive::mimetype; 19 | response["body"] = body; 20 | } 21 | -------------------------------------------------------------------------------- /modules/comet/src/shared/raise.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #ifdef __COMET_CLIENT__ 3 | # include 4 | #endif 5 | 6 | namespace Crails 7 | { 8 | void raise(const std::exception& e) 9 | { 10 | #ifdef __CHEERP_CLIENT__ 11 | Comet::raise(e); 12 | #else 13 | throw e; 14 | #endif 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /modules/crud/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(crails-crud) 4 | 5 | include_directories(.) 6 | 7 | file(GLOB crails_crud src/*.cpp) 8 | file(GLOB headers_crails_crud crails/crud/*.hpp) 9 | file(GLOB scripts_crud_module scripts/modules/crud/*.rb) 10 | 11 | add_library(crails-crud${crails-suffix} SHARED ${crails_crud}) 12 | 13 | install(FILES ${headers_crails_crud} DESTINATION include/crails/crud) 14 | install(FILES ${scripts_crud_module} DESTINATION share/crails/scripts/modules/crud) 15 | install(TARGETS crails-crud${crails-suffix} LIBRARY DESTINATION lib) 16 | -------------------------------------------------------------------------------- /modules/crud/crails/crud/belongs_to_controller.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BELONGS_TO_CONTROLLER_HPP 2 | # define BELONGS_TO_CONTROLLER_HPP 3 | 4 | # include 5 | # include 6 | # include 7 | # include 8 | # include "controller.hpp" 9 | 10 | namespace Crud 11 | { 12 | template 13 | class BelongsToController : public Crud::Controller 14 | { 15 | typedef Crud::Controller Super; 16 | public: 17 | BelongsToController(Crails::Params& params) : Super(params) 18 | {} 19 | 20 | void initialize() 21 | { 22 | Super::initialize(); 23 | initialize_parent_resource(); 24 | } 25 | 26 | void initialize_parent_resource() 27 | { 28 | if (has_parent_id_param()) 29 | { 30 | auto parent_id = Super::params["parent_id"].template as(); 31 | auto query = odb::query::id == parent_id; 32 | 33 | if (!(Super::database.find_one(parent_resource, query))) 34 | Super::response["status"] = Super::ResponseStatus::not_found; 35 | } 36 | } 37 | 38 | bool has_parent_id_param() const 39 | { 40 | std::string parent_id = Super::params["parent_id"].template defaults_to("root"); 41 | 42 | return parent_id != "all" && parent_id != "root"; 43 | } 44 | 45 | protected: 46 | std::shared_ptr parent_resource; 47 | }; 48 | } 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /modules/crud/crails/crud/paginator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PAGINATOR_HPP 2 | # define PAGINATOR_HPP 3 | 4 | # include 5 | # include 6 | # include 7 | 8 | class Paginator 9 | { 10 | static const unsigned int max_items_per_page; 11 | static const unsigned int default_items_per_page; 12 | public: 13 | Paginator(Data params) : params(params) 14 | { 15 | } 16 | 17 | template 18 | void decorate_query(odb::query& query) const 19 | { 20 | if (enabled) 21 | { 22 | query = MODEL::default_order_by(query) 23 | + "LIMIT" + odb::query::_val(get_items_per_page()) 24 | + "OFFSET" + odb::query::_val(get_current_offset()); 25 | } 26 | } 27 | 28 | void decorate_view(Crails::SharedVars& vars, std::function get_total_items) const 29 | { 30 | vars["with_paginator"] = enabled; 31 | if (enabled) 32 | { 33 | vars["page"] = get_current_page(); 34 | vars["items_per_page"] = get_items_per_page(); 35 | vars["items_count"] = get_total_items(); 36 | } 37 | } 38 | 39 | void set_enabled(bool enabled) { this->enabled = enabled; } 40 | bool is_enabled() const { return enabled; } 41 | unsigned int get_items_per_page() const; 42 | unsigned int get_current_offset() const; 43 | unsigned int get_current_page() const; 44 | 45 | private: 46 | bool enabled = true; 47 | Data params; 48 | }; 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /modules/crud/scripts/modules/crud/install.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | $: << "#{ENV['CRAILS_SHARED_DIR']}/scripts/lib" 4 | 5 | require 'cmakelists' 6 | 7 | cmake = CMakeLists.new 8 | cmake.add_crails_module 'crud' 9 | 10 | cmake.write 11 | -------------------------------------------------------------------------------- /modules/crud/src/paginator.cpp: -------------------------------------------------------------------------------- 1 | #include "crails/crud/paginator.hpp" 2 | 3 | const unsigned int Paginator::max_items_per_page = 300; 4 | const unsigned int Paginator::default_items_per_page = 100; 5 | 6 | unsigned int Paginator::get_items_per_page() const 7 | { 8 | unsigned int items_per_page = params["count"].defaults_to(default_items_per_page); 9 | 10 | return std::min(items_per_page, max_items_per_page); 11 | } 12 | 13 | unsigned int Paginator::get_current_page() const 14 | { 15 | return params["page"].defaults_to(0); 16 | } 17 | 18 | unsigned int Paginator::get_current_offset() const 19 | { 20 | return get_items_per_page() * get_current_page(); 21 | } 22 | -------------------------------------------------------------------------------- /modules/docker/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | project(crails-docker) 4 | 5 | file(GLOB_RECURSE docker_template app/docker/*) 6 | file(GLOB scripts_docker_module scripts/modules/docker/*.rb) 7 | file(GLOB lib_scripts scripts/lib/*.rb) 8 | 9 | install(FILES ${docker_template} DESTINATION share/crails/app_template/docker) 10 | install(FILES ${scripts_docker_module} DESTINATION share/crails/scripts/modules/docker) 11 | install(FILES ${lib_scripts} DESTINATION share/crails/scripts/lib) 12 | -------------------------------------------------------------------------------- /modules/docker/app/docker/base/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:buster 2 | 3 | ENV LD_LIBRARY_PATH /usr/local/lib 4 | 5 | RUN apt-get -y --allow-unauthenticated update && \ 6 | apt-get -y --allow-unauthenticated upgrade && \ 7 | apt-get -y install wget \ 8 | cmake \ 9 | build-essential \ 10 | libbz2-dev \ 11 | libssl-dev \ 12 | git \ 13 | ruby \ 14 | ruby-bundler \ 15 | ruby-dev \ 16 | nodejs 17 | 18 | # Downgrade to gcc-7 to solve compatibility issues with odb 2.5 19 | RUN apt-get -y install gcc-7 g++-7 gcc-7-plugin-dev 20 | RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 20 21 | RUN update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-7 20 22 | 23 | WORKDIR /tmp/compile-dir 24 | 25 | # BEGIN Crails dependencies 26 | COPY boost.sh boost.sh 27 | RUN bash /tmp/compile-dir/boost.sh 28 | 29 | COPY cppnetlib.sh cppnetlib.sh 30 | RUN bash ./cppnetlib.sh 31 | # END Crails dependencies 32 | 33 | COPY crails.sh crails.sh 34 | RUN bash ./crails.sh 35 | ENV CRAILS_SHARED_DIR /usr/local/share/crails 36 | 37 | # BEGIN Dependencies 38 | # END Dependencies 39 | 40 | RUN mkdir -p /opt/webapp 41 | WORKDIR /opt/webapp 42 | ENV CRAILS_RUBY_BUNDLE_PATH /opt/webapp/docker 43 | COPY package.sh /usr/local/bin/package.sh 44 | RUN chmod +x /usr/local/bin/package.sh 45 | -------------------------------------------------------------------------------- /modules/docker/app/docker/base/boost.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | boost_version_major="1" 4 | boost_version_minor="72" 5 | boost_version_patch="0" 6 | boost_directory="boost_${boost_version_major}_${boost_version_minor}_${boost_version_patch}" 7 | 8 | wget http://sourceforge.net/projects/boost/files/boost/${boost_version_major}.${boost_version_minor}.${boost_version_patch}/boost_${boost_version_major}_${boost_version_minor}_${boost_version_patch}.tar.gz/download 9 | tar -zxvf download && rm download 10 | 11 | cd "${boost_directory}" 12 | ./bootstrap.sh \ 13 | --with-toolset=gcc \ 14 | --without-libraries=python 15 | ./b2 thread filesystem program_options system 16 | ./b2 install 17 | -------------------------------------------------------------------------------- /modules/docker/app/docker/base/cppnetlib.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # cppnetlib-0.13.0-final.tar.gz won't compile with the latest version of boost 4 | #cppnetlib_version="0.13.0" 5 | #cppnetlib_release="final" 6 | #cppnetlib_filename="cpp-netlib-${cppnetlib_version}-${cppnetlib_release}.tar.gz" 7 | 8 | #wget http://downloads.cpp-netlib.org/${cppnetlib_version}/${cppnetlib_filename} 9 | #tar -zxvf ${cppnetlib_filename} && rm ${cppnetlib_filename} 10 | 11 | #cd cpp-netlib-${cppnetlib_version}-${cppnetlib_release} 12 | #cmake . && make && make install 13 | 14 | ## 15 | ## Installing from git 16 | ## 17 | git clone https://github.com/cpp-netlib/cpp-netlib.git 18 | 19 | mkdir cpp-netlib/build 20 | cd cpp-netlib/build 21 | 22 | git checkout 0.13-release 23 | 24 | git submodule init 25 | git submodule update 26 | 27 | ## Patch to make cpp-netlib 0.13 compatible with boost >= 1.70 28 | file_to_patch="boost/network/protocol/stream_handler.hpp" 29 | line_to_remove=`grep -n "#include " "../$file_to_patch" | cut -d':' -f1` 30 | 31 | if [[ $line_to_remove != "" ]] ; then 32 | sed $line_to_remove'd' "../$file_to_patch" > tmp 33 | mv tmp "../$file_to_patch" 34 | fi 35 | ## END PATCH 36 | 37 | cmake -DCMAKE_CXX_FLAGS=-std=c++11 \ 38 | -DCPP-NETLIB_BUILD_TESTS=OFF \ 39 | -DCPP-NETLIB_BUILD_EXAMPLES=OFF \ 40 | -DCPP-NETLIB_BUILD_SHARED_LIBS=ON \ 41 | -DUri_BUILD_TESTS=OFF \ 42 | -DUri_WARNINGS_AS_ERRORS=OFF \ 43 | .. 44 | 45 | make 46 | make install 47 | -------------------------------------------------------------------------------- /modules/docker/app/docker/base/crails.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | git clone https://github.com/Plaristote/crails.git 4 | cd crails 5 | 6 | mkdir build 7 | cd build 8 | 9 | cmake .. -DDEVELOPER_MODE=OFF 10 | make clean && make && make install 11 | rm CMakeCache.txt 12 | 13 | cmake .. -DDEVELOPER_MODE=ON 14 | make clean && make && make install 15 | rm CMakeCache.txt 16 | -------------------------------------------------------------------------------- /modules/docker/app/docker/deploy: -------------------------------------------------------------------------------- 1 | #!/bin/sh -ex 2 | 3 | ## 4 | ## Set environment variables 5 | ## 6 | heroku config $* | grep LD_LIBRARY_PATH 7 | if [[ $? != 0 ]] ; then 8 | heroku config:set LD_LIBRARY_PATH=/app/lib:/app/bin $* 9 | heroku config:set BUILDPACK_URL=https://github.com/Plaristote/heroku-buildpack-crails $* 10 | fi 11 | 12 | ## 13 | ## Initialize repository 14 | ## 15 | mkdir -p docker/crails-build 16 | cd docker/crails-build 17 | 18 | if [[ -f .git ]] ; then 19 | echo 'found git' 20 | else 21 | git init . 22 | heroku git:remote $* 23 | git pull heroku master 24 | fi 25 | 26 | 27 | ## 28 | ## Build the package 29 | ## 30 | cd ../.. 31 | 32 | docker/build 33 | 34 | cd docker/crails-build 35 | 36 | ## 37 | ## Deploy 38 | ## 39 | git add . 40 | git commit --amend -m "crails heroku deployer was here" 41 | git push -f heroku master 42 | -------------------------------------------------------------------------------- /modules/docker/app/docker/gitignore: -------------------------------------------------------------------------------- 1 | crails-app/ 2 | crails-build/ 3 | -------------------------------------------------------------------------------- /modules/docker/app/docker/package.erb: -------------------------------------------------------------------------------- 1 | #!/bin/sh -ex 2 | 3 | machine_name="<%= project_name %>_dock" 4 | 5 | docker build -t "$machine_name" docker/base 6 | 7 | mkdir -p docker/runtime 8 | 9 | docker run -it --rm \ 10 | -v "`pwd`:/opt/webapp" \ 11 | "$machine_name" /opt/webapp/docker/scripts/package.sh 12 | -------------------------------------------------------------------------------- /modules/docker/app/docker/shell.erb: -------------------------------------------------------------------------------- 1 | #!/bin/sh -ex 2 | 3 | machine_name="<%= project_name %>_dock" 4 | docker_build_options="-q" 5 | docker_options="-it" 6 | command="bash" 7 | 8 | while getopts "vac:h" option 9 | do 10 | case $option in 11 | v) 12 | docker_build_options="" 13 | ;; 14 | a) 15 | docker_options="-t" 16 | ;; 17 | c) 18 | command="$OPTARG" 19 | ;; 20 | h) 21 | echo "Usage: $0 [OPTIONS]" 22 | echo " -v Verbose docker build (quiet by default)" 23 | echo " -a Disable interactive mode. This option must be set when the command isn't launched from an interactive shell" 24 | echo " -c [CMD] Will run 'CMD' instead of opening a shell" 25 | exit 0 26 | ;; 27 | esac 28 | done 29 | 30 | mkdir -p docker/build docker/.bundle 31 | 32 | docker build $docker_build_options -t "$machine_name" docker/base 33 | 34 | docker run --net=host $docker_options --rm \ 35 | -v "`pwd`:/opt/webapp" \ 36 | -v "`pwd`/docker/output:/opt/webapp/build" \ 37 | -v "`pwd`/docker/.bundle:/opt/webapp/.bundle" \ 38 | "$machine_name" $command 39 | -------------------------------------------------------------------------------- /modules/docker/scripts/lib/dockerfile.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | class Dockerfile 4 | def initialize 5 | @source_file = 'docker/base/Dockerfile' 6 | @content = File.read @source_file 7 | end 8 | 9 | def write 10 | File.open(@source_file, 'w') do |file| 11 | file.write @content 12 | end 13 | puts "\033[32m[EDITED]\033[0m " + @source_file 14 | end 15 | 16 | def add_compile_file file 17 | commands = "\nCOPY #{file} #{file}\nRUN bash ./#{file}" 18 | prepend_to "# END Dependencies", commands 19 | end 20 | 21 | def add_crails_compile_file file 22 | commands = "\nCOPY #{file} #{file}\nRUN bash ./#{file}" 23 | prepend_to "# END Crails dependencies", commands 24 | end 25 | 26 | def add_system_dependency package 27 | @content.gsub!("nodejs", "nodejs \\\n #{package}") 28 | end 29 | 30 | private 31 | def prepend_to footer, str 32 | @content.gsub!(footer, "#{str}\n#{footer}") 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /modules/docker/scripts/modules/docker/add-module.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | $: << "#{ENV['CRAILS_SHARED_DIR']}/scripts/lib" 4 | 5 | class CrailsDockerBase 6 | def crails_compile_files ; [] ; end 7 | def compile_files ; [] ; end 8 | def system_dependencies ; [] ; end 9 | end 10 | 11 | require 'dockerfile' 12 | require 'project_model' 13 | require "docker_#{ARGV[0]}_plugin" 14 | 15 | dockerfile = Dockerfile.new 16 | docker_plugin = CrailsDocker.new 17 | project = ProjectModel.new 18 | source = "#{ENV['CRAILS_SHARED_DIR']}/app_template/docker" 19 | 20 | project.base_directory source, Dir.pwd do 21 | project.directory :docker do 22 | project.directory :base do 23 | (docker_plugin.compile_files + docker_plugin.crails_compile_files).each do |file| 24 | project.file file 25 | end 26 | end 27 | end 28 | end 29 | 30 | docker_plugin.crails_compile_files.each do |file| 31 | dockerfile.add_crails_compile_file file 32 | end 33 | 34 | docker_plugin.compile_files.each do |file| 35 | dockerfile.add_compile_file file 36 | end 37 | 38 | docker_plugin.system_dependencies.each do |package| 39 | dockerfile.add_system_dependency package 40 | end 41 | 42 | dockerfile.write 43 | -------------------------------------------------------------------------------- /modules/docker/scripts/modules/docker/install.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | $: << "#{ENV['CRAILS_SHARED_DIR']}/scripts/lib" 4 | 5 | # Dummy Guard::Plugin implementation to include Guard::CrailsPlugin 6 | module ::Guard 7 | class Plugin 8 | end 9 | end 10 | 11 | require 'project_model' 12 | require "#{ENV['CRAILS_SHARED_DIR']}/guard/crails-base" 13 | 14 | project_name = Guard::CrailsPlugin.new.get_cmake_variable 'CMAKE_PROJECT_NAME:STATIC' 15 | project = ProjectModel.new 16 | base_directory = "#{Dir.pwd}/docker" 17 | source = "#{ENV['CRAILS_SHARED_DIR']}/app_template/docker" 18 | 19 | project.base_directory source, Dir.pwd do 20 | project.directory :docker do 21 | project.file '.gitignore', 'gitignore' 22 | project.generate_erb 'package', 'package.erb', binding: binding 23 | project.generate_erb 'shell', 'shell.erb', binding: binding 24 | project.directory :base do 25 | project.file 'Dockerfile' 26 | project.file 'crails.sh' 27 | project.file 'cppnetlib.sh' 28 | project.file 'boost.sh' 29 | project.file 'package.sh' 30 | end 31 | end 32 | end 33 | 34 | FileUtils.chmod 'ug+x', [ 'docker/package', 'docker/shell' ] 35 | 36 | -------------------------------------------------------------------------------- /modules/docker/scripts/modules/docker/uninstall.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | require 'fileutils' 4 | 5 | FileUtils.rm_r "#{Dir.pwd}/docker" 6 | -------------------------------------------------------------------------------- /modules/html/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(crails-html) 4 | 5 | include_directories(.) 6 | 7 | file(GLOB_RECURSE crails_html src/*.cpp) 8 | file(GLOB guard_html_plugins scripts/guard/*.rb) 9 | file(GLOB scripts_html_templates scripts/guard/templates/*.erb) 10 | file(GLOB scripts_html_module scripts/modules/html/*.rb) 11 | file(GLOB html_templates app/lib/exception.ecpp) 12 | 13 | add_library(crails-html${crails-suffix} SHARED ${crails_html}) 14 | 15 | install(DIRECTORY crails DESTINATION include) 16 | install(FILES ${scripts_html_templates} DESTINATION share/crails/guard/templates) 17 | install(FILES ${scripts_html_module} DESTINATION share/crails/scripts/modules/html) 18 | install(FILES ${html_templates} DESTINATION share/crails/app_template/html) 19 | install(FILES ${guard_html_plugins} DESTINATION share/crails/guard) 20 | install(TARGETS crails-html${crails-suffix} LIBRARY DESTINATION lib) 21 | -------------------------------------------------------------------------------- /modules/html/crails/html_template.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTML_TEMPLATE_HPP 2 | # define HTML_TEMPLATE_HPP 3 | 4 | # include 5 | # include 6 | 7 | namespace Crails 8 | { 9 | class HtmlTemplate : public Template 10 | { 11 | public: 12 | typedef std::function Yieldable; 13 | 14 | HtmlTemplate(const Renderer* renderer, SharedVars& vars) : 15 | Template(renderer, vars) 16 | { 17 | } 18 | 19 | static std::string html_escape(const std::string& data); 20 | static std::string tag(const std::string& name, const std::map& attrs); 21 | static std::string tag(const std::string& name, const std::map& attrs, Yieldable); 22 | static std::string tag(const std::string& name, Yieldable); 23 | }; 24 | } 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /modules/html/crails/renderers/html_renderer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTML_RENDERER_HPP 2 | # define HTML_RENDERER_HPP 3 | 4 | # include 5 | 6 | namespace Crails 7 | { 8 | class HtmlRenderer : public Renderer 9 | { 10 | public: 11 | HtmlRenderer(); 12 | 13 | bool can_render(const std::string& accept_header, const std::string& view) const; 14 | void render_template(const std::string& view, Data params, Data response, SharedVars& vars) const; 15 | }; 16 | } 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /modules/html/scripts/guard/templates/html_renderer.cpp.erb: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace Crails; 4 | using namespace std; 5 | 6 | <% templates.each do |template| -%> 7 | string <%= template[:function] %>(const Renderer*, SharedVars&); 8 | <% end -%> 9 | 10 | HtmlRenderer::HtmlRenderer() 11 | { 12 | <% templates.each do |template| -%> 13 | templates.insert( 14 | pair(<%= template[:name].inspect %>, <%= template[:function] %>) 15 | ); 16 | <% end -%> 17 | } 18 | -------------------------------------------------------------------------------- /modules/html/scripts/guard/templates/html_template.cpp.erb: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | <%= include_lines.join "\n" -%> 6 | 7 | using namespace std; 8 | 9 | class <%= class_name %> : public Crails::HtmlTemplate 10 | { 11 | public: 12 | <%= class_name %>(const Crails::Renderer* renderer, Crails::SharedVars& vars) : 13 | HtmlTemplate(renderer, vars)<%= ',' if lines[:variables_initialization].count > 0 %> 14 | <%= lines[:variables_initialization].join ",\n" %> 15 | { 16 | } 17 | 18 | std::string render(void) 19 | { 20 | <%= lines[:linking_lines].join "\n" %> 21 | <%= code %> 22 | return (<%= out_var %>.str()); 23 | } 24 | 25 | private: 26 | std::stringstream <%= out_var %>; 27 | <%= lines[:instance_variables].join "\n" %> 28 | }; 29 | 30 | std::string <%= function_name %>(const Crails::Renderer* renderer, Crails::SharedVars& vars) 31 | { 32 | <%= class_name %> view(renderer, vars); 33 | 34 | return (view.render()); 35 | } 36 | 37 | -------------------------------------------------------------------------------- /modules/html/scripts/modules/html/install.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | $: << "#{ENV['CRAILS_SHARED_DIR']}/scripts/lib" 4 | 5 | require 'project_model' 6 | require 'cmakelists' 7 | require 'maincpp' 8 | 9 | project = ProjectModel.new 10 | base_directory = Dir.pwd 11 | source = "#{ENV['CRAILS_SHARED_DIR']}/guard/templates" 12 | 13 | project.base_directory source, base_directory do 14 | project.directory :lib do 15 | project.directory :renderers do 16 | templates = [] 17 | project.generate_erb 'html.cpp', 'html_renderer.cpp.erb', :binding => binding 18 | end 19 | end 20 | end 21 | 22 | source = "#{ENV['CRAILS_SHARED_DIR']}/app_template/html" 23 | project.base_directory source, base_directory do 24 | project.directory :lib do 25 | project.file 'exception.ecpp' 26 | end 27 | end 28 | 29 | cmake = CMakeLists.new 30 | cmake.add_crails_module 'html' 31 | 32 | renderers_cpp = RenderersCppEditor.new 33 | renderers_cpp.add_include 'crails/renderers/html_renderer.hpp' 34 | renderers_cpp.add_initializer 'renderers.push_back(new HtmlRenderer);' 35 | 36 | guardfile = GuardfileEditor.new 37 | guardfile.add_task 'before_compile', < 2 | 3 | using namespace std; 4 | using namespace Crails; 5 | 6 | bool HtmlRenderer::can_render(const std::string& accept_header, const std::string& view) const 7 | { 8 | if (accept_header.find("text/html") != std::string::npos 9 | || accept_header.find("*/*") != std::string::npos 10 | || accept_header.find("text/*") != std::string::npos) 11 | return templates.find(view) != templates.end(); 12 | return (false); 13 | } 14 | 15 | void HtmlRenderer::render_template(const std::string& view, Data params, Data response, SharedVars& vars) const 16 | { 17 | auto tpl = templates.find(view); 18 | string html_view = (*tpl).second(this, vars); 19 | string layout = response["layout"].defaults_to(""); 20 | 21 | response["headers"]["Content-Type"] = "text/html"; 22 | if (layout != "" && view != layout) 23 | { 24 | if (can_render("text/html", layout)) 25 | { 26 | vars["yield"] = &html_view; 27 | render_template(layout, params, response, vars); 28 | } 29 | else 30 | throw MissingTemplate(layout); 31 | } 32 | else 33 | response["body"] = html_view; 34 | } 35 | -------------------------------------------------------------------------------- /modules/html/src/html_template.cpp: -------------------------------------------------------------------------------- 1 | #include "crails/html_template.hpp" 2 | 3 | using namespace Crails; 4 | using namespace std; 5 | 6 | string HtmlTemplate::html_escape(const string& data) 7 | { 8 | string buffer; 9 | 10 | buffer.reserve(data.size()); 11 | for(size_t pos = 0; pos != data.size(); ++pos) { 12 | switch(data[pos]) { 13 | case '&': buffer.append("&"); break; 14 | case '\"': buffer.append("""); break; 15 | case '\'': buffer.append("'"); break; 16 | case '<': buffer.append("<"); break; 17 | case '>': buffer.append(">"); break; 18 | default: buffer.append(&data[pos], 1); break; 19 | } 20 | } 21 | return buffer; 22 | } 23 | 24 | string HtmlTemplate::tag(const string& name, const map& attrs) 25 | { 26 | return tag(name, attrs, Yieldable()); 27 | } 28 | 29 | string HtmlTemplate::tag(const string& name, Yieldable content) 30 | { 31 | return tag(name, {}, content); 32 | } 33 | 34 | string HtmlTemplate::tag(const string& name, const map& attrs, Yieldable content) 35 | { 36 | stringstream html_stream; 37 | 38 | html_stream << '<' << name; 39 | for (const auto& attr : attrs) 40 | { 41 | html_stream << ' ' << attr.first << "=\""; 42 | for (size_t i = 0 ; i < attr.second.length() ; ++i) 43 | { 44 | if (attr.second[i] == '\\' || attr.second[i] == '"') 45 | html_stream << '\\'; 46 | html_stream << attr.second[i]; 47 | } 48 | html_stream << '"'; 49 | } 50 | html_stream << '>'; 51 | if (content) 52 | html_stream << content(); 53 | html_stream << "'; 54 | return html_stream.str(); 55 | } 56 | -------------------------------------------------------------------------------- /modules/image/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(crails-image) 4 | 5 | include_directories(. ${ImageMagick_Magick++_INCLUDE_DIRS}) 6 | 7 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMAGICKCORE_QUANTUM_DEPTH=16") 8 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMAGICKCORE_HDRI_ENABLE=0") 9 | 10 | file(GLOB crails_image src/*.cpp) 11 | file(GLOB headers_crails_image crails/*.hpp) 12 | file(GLOB scripts_image_module scripts/modules/image/*.rb) 13 | file(GLOB lib_scripts scripts/lib/*.rb) 14 | file(GLOB_RECURSE image_app_template app/*) 15 | 16 | add_library(crails-image${crails-suffix} SHARED ${crails_image}) 17 | install(FILES ${headers_crails_image} DESTINATION include/crails) 18 | install(FILES ${scripts_image_module} DESTINATION share/crails/scripts/modules/image) 19 | install(FILES ${lib_scripts} DESTINATION share/crails/scripts/lib) 20 | install(FILES ${image_app_template} DESTINATION share/crails/app_template/image) 21 | install(TARGETS crails-image${crails-suffix} LIBRARY DESTINATION lib) 22 | -------------------------------------------------------------------------------- /modules/image/app/config/images.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace Crails; 4 | 5 | const std::string BasicImage::default_store_path = "crails-image"; 6 | const std::string BasicImage::default_image_path = "default-image.png"; 7 | const unsigned short BasicImage::default_image_quality = 80; 8 | -------------------------------------------------------------------------------- /modules/image/app/docker/base/compile-magick++.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -ex 2 | 3 | imagemagick_version="6.7.7-10" 4 | wget "http://www.imagemagick.org/download/releases/ImageMagick-$imagemagick_version.tar.xz" 5 | tar xvfJ ImageMagick-$imagemagick_version.tar.xz 6 | cd ImageMagick-$imagemagick_version 7 | ./configure 8 | make && make install 9 | 10 | rm /usr/local/lib/libMagick{Core,Wand}.so.5 11 | -------------------------------------------------------------------------------- /modules/image/scripts/lib/docker_image_plugin.rb: -------------------------------------------------------------------------------- 1 | class CrailsDocker < CrailsDockerBase 2 | def crails_compile_files 3 | ["compile-magick++.sh"] 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /modules/image/scripts/modules/image/install.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | $: << "#{ENV['CRAILS_SHARED_DIR']}/scripts/lib" 4 | 5 | require 'project_model' 6 | require 'cmakelists' 7 | require 'maincpp' 8 | 9 | project = ProjectModel.new 10 | base_directory = Dir.pwd 11 | source = ENV['CRAILS_SHARED_DIR'] + '/app_template/image' 12 | backends = ['mysql', 'postgresql', 'sqlite3'] 13 | 14 | project.base_directory source, base_directory do 15 | project.directory :config do 16 | project.file 'images.cpp' 17 | end 18 | end 19 | 20 | cmake = CMakeLists.new 21 | cmake.add_find_package 'ImageMagick COMPONENTS Magick++ REQUIRED' 22 | cmake.add_include_directories '${ImageMagick_Magick++_INCLUDE_DIRS}' 23 | cmake.add_dependency '${ImageMagick_Magick++_LIBRARY}' 24 | cmake.add_crails_module 'image' 25 | cmake.write 26 | -------------------------------------------------------------------------------- /modules/json/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(crails-json) 4 | 5 | include_directories(.) 6 | 7 | file(GLOB crails_json src/json_renderer.cpp src/json_template.cpp) 8 | file(GLOB guard_json_plugins scripts/guard/*.rb) 9 | file(GLOB scripts_json_templates scripts/guard/templates/*.erb) 10 | file(GLOB scripts_json_module scripts/modules/json/*.rb) 11 | file(GLOB json_templates app/lib/exception.cjson) 12 | 13 | add_library(crails-json${crails-suffix} SHARED ${crails_json}) 14 | 15 | install(DIRECTORY crails DESTINATION include) 16 | install(FILES ${scripts_json_templates} DESTINATION share/crails/guard/templates) 17 | install(FILES ${scripts_json_module} DESTINATION share/crails/scripts/modules/json) 18 | install(FILES ${guard_json_plugins} DESTINATION share/crails/guard) 19 | install(FILES ${json_templates} DESTINATION share/crails/app_template/json) 20 | install(TARGETS crails-json${crails-suffix} LIBRARY DESTINATION lib) 21 | -------------------------------------------------------------------------------- /modules/json/app/lib/exception.cjson: -------------------------------------------------------------------------------- 1 | // BEGIN LINKING 2 | #include 3 | 4 | using namespace Crails; 5 | using namespace std; 6 | 7 | string @exception_name; 8 | string @exception_what; 9 | Params& @params; 10 | 11 | // END LINKING 12 | 13 | json >("exception", [=]() 14 | { 15 | json("type", exception_name); 16 | json("what", exception_what); 17 | 18 | if (params["controller-data"].exists()) 19 | { 20 | json >("controller", [=]() 21 | { 22 | json("type", params["controller-data"]["name"].defaults_to("")); 23 | json("method", params["controller-data"]["action"].defaults_to("")); 24 | }); 25 | params["controller-data"].destroy(); 26 | } 27 | 28 | if (params["backtrace"].exists()) 29 | { 30 | json("backtrace", params["backtrace"].as()); 31 | params["backtrace"].destroy(); 32 | } 33 | 34 | json("params", params.as_data()); 35 | json("session", params.get_session()); 36 | }); 37 | -------------------------------------------------------------------------------- /modules/json/crails/renderers/json_renderer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef JSON_RENDERER_HPP 2 | # define JSON_RENDERER_HPP 3 | 4 | # include 5 | 6 | namespace Crails 7 | { 8 | class JsonRenderer : public Renderer 9 | { 10 | public: 11 | JsonRenderer(); 12 | 13 | bool can_render(const std::string& accept_header, const std::string& view) const; 14 | void render_template(const std::string& view, Data params, Data response, SharedVars& vars) const; 15 | }; 16 | } 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /modules/json/scripts/guard/crails-cjson.rb: -------------------------------------------------------------------------------- 1 | require 'guard/crails-base-templates' 2 | require 'guard/crails-notifier' 3 | 4 | module ::Guard 5 | class CrailsCjson < CrailsTemplatePlugin 6 | def initialize arg 7 | super arg 8 | @base_path = "app/views/" 9 | @template_type = "json" 10 | @extension = "cjson" 11 | end 12 | 13 | def compile_json filename 14 | file_content = (File.open filename).read 15 | view_name, class_name, function_name = get_names filename 16 | 17 | lines = file_content.split /\r?\n/ 18 | include_lines, linking_lines, content_lines = process_lines lines 19 | lines = process_linking_lines linking_lines 20 | code = process_linked_variables(content_lines.join "\n") 21 | write_template_to_file(filename, instance_eval { binding }) 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /modules/json/scripts/guard/templates/json_renderer.cpp.erb: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace Crails; 4 | using namespace std; 5 | 6 | <% templates.each do |template| -%> 7 | string <%= template[:function] %>(const Renderer*, SharedVars&); 8 | <% end -%> 9 | 10 | JsonRenderer::JsonRenderer() 11 | { 12 | <% templates.each do |template| -%> 13 | templates.insert( 14 | pair(<%= template[:name].inspect %>, <%= template[:function] %>) 15 | ); 16 | <% end -%> 17 | } 18 | -------------------------------------------------------------------------------- /modules/json/scripts/guard/templates/json_template.cpp.erb: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | <%= include_lines.join "\n" -%> 6 | 7 | using namespace std; 8 | 9 | class <%= class_name %> : public Crails::JsonTemplate 10 | { 11 | public: 12 | <%= class_name %>(const Crails::Renderer* renderer, Crails::SharedVars& vars) : 13 | JsonTemplate(renderer, vars)<%= ',' if lines[:variables_initialization].count > 0 %> 14 | <%= lines[:variables_initialization].join ",\n" %> 15 | { 16 | } 17 | 18 | std::string render(void) 19 | { 20 | <%= lines[:linking_lines].join "\n" %> 21 | stream << '{'; 22 | <%= code %> 23 | stream << '}'; 24 | return (stream.str()); 25 | } 26 | 27 | private: 28 | <%= lines[:instance_variables].join "\n" %> 29 | }; 30 | 31 | std::string <%= function_name %>(const Crails::Renderer* renderer, Crails::SharedVars& vars) 32 | { 33 | <%= class_name %> _template(renderer, vars); 34 | 35 | return (_template.render()); 36 | } 37 | 38 | -------------------------------------------------------------------------------- /modules/json/scripts/modules/json/install.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | $: << "#{ENV['CRAILS_SHARED_DIR']}/scripts/lib" 4 | 5 | require 'project_model' 6 | require 'cmakelists' 7 | require 'maincpp' 8 | 9 | project = ProjectModel.new 10 | base_directory = Dir.pwd 11 | source = "#{ENV['CRAILS_SHARED_DIR']}/guard/templates" 12 | 13 | project.base_directory source, base_directory do 14 | project.directory :lib do 15 | project.directory :renderers do 16 | templates = [] 17 | project.generate_erb 'json.cpp', 'json_renderer.cpp.erb', :binding => binding 18 | end 19 | end 20 | end 21 | 22 | source = "#{ENV['CRAILS_SHARED_DIR']}/app_template/json" 23 | project.base_directory source, base_directory do 24 | project.directory :lib do 25 | project.file 'exception.cjson' 26 | end 27 | end 28 | 29 | cmake = CMakeLists.new 30 | cmake.add_crails_module 'json' 31 | 32 | renderers_cpp = RenderersCppEditor.new 33 | renderers_cpp.add_include 'crails/renderers/json_renderer.hpp' 34 | renderers_cpp.add_initializer 'renderers.push_back(new JsonRenderer);' 35 | 36 | guardfile = GuardfileEditor.new 37 | guardfile.add_task 'before_compile', < 2 | 3 | using namespace Crails; 4 | 5 | bool JsonRenderer::can_render(const std::string& accept_header, const std::string& view) const 6 | { 7 | if (accept_header.find("/json") != std::string::npos 8 | || accept_header.find("*/*") != std::string::npos) 9 | return templates.find(view) != templates.end(); 10 | return false; 11 | } 12 | 13 | void JsonRenderer::render_template(const std::string& view, Data params, Data response, SharedVars& vars) const 14 | { 15 | auto tpl = templates.find(view); 16 | std::string json_view = (*tpl).second(this, vars); 17 | 18 | response["headers"]["Content-Type"] = "application/json"; 19 | response["body"] = json_view; 20 | } 21 | -------------------------------------------------------------------------------- /modules/mail/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(crails-mail) 4 | 5 | include_directories(.) 6 | 7 | file(GLOB crails_mail 8 | src/mailer.cpp 9 | src/mail_servers.cpp 10 | src/smtp.cpp) 11 | 12 | file(GLOB headers_crails_mail 13 | crails/mailer.hpp 14 | crails/mail_servers.hpp 15 | crails/smtp.hpp) 16 | 17 | file(GLOB crails_mail_templates 18 | app/config/mailers.json) 19 | 20 | file(GLOB crails_mail_scripts 21 | scripts/modules/mail/*.rb) 22 | 23 | add_library(crails-mail${crails-suffix} SHARED ${crails_mail}) 24 | 25 | install(FILES ${headers_crails_mail} DESTINATION include/crails) 26 | install(FILES ${crails_mail_templates} DESTINATION share/crails/app_template/mail) 27 | install(FILES ${crails_mail_scripts} DESTINATION share/crails/scripts/modules/mail) 28 | install(TARGETS crails-mail${crails-suffix} LIBRARY DESTINATION lib) 29 | -------------------------------------------------------------------------------- /modules/mail/app/config/mailers.json: -------------------------------------------------------------------------------- 1 | { 2 | "gmail": { 3 | "hostname": "smtp.gmail.com", 4 | "port": 465, 5 | "tls": "true" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /modules/mail/crails/mail_servers.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MAIL_SERVERS_HPP 2 | # define MAIL_SERVERS_HPP 3 | 4 | # include 5 | # include 6 | # include 7 | # include 8 | 9 | namespace Crails 10 | { 11 | class MailServers 12 | { 13 | SINGLETON(MailServers) 14 | public: 15 | void configure_mail_server(const std::string& conf_name, Smtp::Server& server) const; 16 | 17 | private: 18 | class Conf 19 | { 20 | public: 21 | Conf(Data server_data); 22 | 23 | void connect_server(Smtp::Server& server) const; 24 | 25 | private: 26 | std::string hostname; 27 | unsigned short port; 28 | bool use_authentication, use_tls; 29 | Smtp::Server::AuthenticationProtocol authentication_protocol; 30 | std::string username; 31 | std::string password; 32 | }; 33 | 34 | typedef std::map ServerConfs; 35 | 36 | MailServers(void); 37 | 38 | void load_mail_servers(Data data); 39 | 40 | ServerConfs server_confs; 41 | DataTree data_tree; 42 | }; 43 | } 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /modules/mail/crails/mailer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MAILER_HPP 2 | # define MAILER_HPP 3 | 4 | # include 5 | # include 6 | # include "mail_servers.hpp" 7 | 8 | namespace Crails 9 | { 10 | class Mailer 11 | { 12 | public: 13 | Mailer(Controller& controller, const std::string& configuration); 14 | Mailer(const std::string& configuration); 15 | 16 | void render(const std::string& view); 17 | void send(void); 18 | 19 | protected: 20 | Smtp::Mail mail; 21 | SharedVars vars; 22 | DataTree params, response; 23 | 24 | private: 25 | Controller* controller; 26 | std::string configuration; 27 | Smtp::Server smtp_server; 28 | bool is_connected; 29 | }; 30 | } 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /modules/mail/scripts/modules/mail/install.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | $: << "#{ENV['CRAILS_SHARED_DIR']}/scripts/lib" 4 | 5 | require 'project_model' 6 | require 'cmakelists' 7 | require 'maincpp' 8 | 9 | project = ProjectModel.new 10 | base_directory = Dir.pwd 11 | source = ENV['CRAILS_SHARED_DIR'] + '/app_template/mail' 12 | 13 | project.base_directory source, base_directory do 14 | project.directory :config do 15 | project.file 'mailers.json' 16 | end 17 | end 18 | 19 | cmake = CMakeLists.new 20 | cmake.add_crails_module 'mail' 21 | 22 | main_cpp = MainCppEditor.new 23 | main_cpp.add_include "crails/mail_servers.hpp" 24 | main_cpp.add_initializer "MailServers::singleton::Initialize();" 25 | main_cpp.add_finalizer "MailServers::singleton::Finalize();" 26 | 27 | cmake.write 28 | main_cpp.write 29 | -------------------------------------------------------------------------------- /modules/mail/src/mailer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | using namespace Crails; 6 | 7 | Mailer::Mailer(Controller& controller, const std::string& configuration) : controller(&controller), configuration(configuration), is_connected(false) 8 | { 9 | } 10 | 11 | Mailer::Mailer(const std::string& configuration) : controller(0), configuration(configuration), is_connected(false) 12 | { 13 | } 14 | 15 | void Mailer::render(const std::string& view) 16 | { 17 | SharedVars& vars = controller ? controller->vars : this->vars; 18 | 19 | if (!params["headers"]["Accept"].exists()) 20 | params["headers"]["Accept"] = "text/html text/plain"; 21 | Renderer::render(view, params.as_data(), response.as_data(), vars); 22 | mail.set_content_type(response["headers"]["Content-Type"].defaults_to("")); 23 | mail.set_body(response["body"].as()); 24 | } 25 | 26 | void Mailer::send(void) 27 | { 28 | if (!is_connected) 29 | { 30 | MailServers::singleton::Get()->configure_mail_server(configuration, smtp_server); 31 | is_connected = true; 32 | } 33 | smtp_server.send(mail); 34 | } 35 | -------------------------------------------------------------------------------- /modules/metarecord/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(crails-models) 4 | 5 | file(GLOB headers_crails_models crails/models/*.hpp) 6 | file(GLOB scripts_models_module scripts/modules/models/*.rb) 7 | 8 | install(FILES ${headers_crails_models} DESTINATION include/crails/models) 9 | install(FILES ${scripts_models_module} DESTINATION share/crails/scripts/modules/models) 10 | -------------------------------------------------------------------------------- /modules/metarecord/scripts/modules/models/install.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | $: << "#{ENV['CRAILS_SHARED_DIR']}/scripts/lib" 4 | 5 | require 'project_model' 6 | require 'cmakelists' 7 | require 'maincpp' 8 | require 'bundle' 9 | 10 | base_modules = ["crails/edit", "crails/data", "crails/destroy", "crails/query"] 11 | optional_modules = ["crails/view", "comet-cpp"] 12 | 13 | puts "/?\\ Which optionals generators do you wish to use ? (separate with commas)" 14 | puts "- Available modules are: #{optional_modules.join ', '}" 15 | print "$> " 16 | STDOUT.flush 17 | picked_modules = base_modules + (gets.chomp.split /\s*,\s*/) 18 | 19 | # Setup comet modules if needed 20 | if picked_modules.include? "comet-cpp" 21 | picked_modules.delete "comet-cpp" 22 | ["edit", "data"].each do |mod| 23 | picked_modules.delete "crails/#{mod}" 24 | picked_modules << "comet/#{mod}" 25 | end 26 | end 27 | 28 | guardfile = GuardfileEditor.new 29 | guardfile.add_task 'before_compile', < 2 | #include 3 | 4 | using namespace Crails; 5 | 6 | USE_SESSION_STORE(MongoStore) 7 | 8 | const std::string MongoStore::SessionStore::collection_name = "session_store"; 9 | const std::string MongoStore::SessionStore::database_name = "mongodb"; 10 | const unsigned int MongoStore::SessionStore::session_expiration = 60 * 30; 11 | -------------------------------------------------------------------------------- /modules/mongodb/app/docker/base/compile-mongo-cxx-driver.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | apt-get install -y scons 4 | 5 | mongodb_version_major="2" 6 | mongodb_version_minor="4" 7 | mongodb_version="${mongodb_version_major}.${mongodb_version_minor}.14" 8 | 9 | git clone https://github.com/mongodb/mongo-cxx-driver 10 | cd mongo-cxx-driver 11 | git checkout legacy 12 | scons --ssl --prefix=/usr/local install 13 | -------------------------------------------------------------------------------- /modules/mongodb/crails/mongodb/array.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MONGODB_ARRAY_HPP 2 | # define MONGODB_ARRAY_HPP 3 | 4 | # include 5 | # include 6 | 7 | namespace MongoDB 8 | { 9 | template 10 | struct Array : public mongo::BSONArray 11 | { 12 | Array() 13 | { 14 | } 15 | 16 | Array(const std::vector& array) 17 | { 18 | mongo::BSONArrayBuilder builder; 19 | 20 | for (unsigned short i = 0 ; i < array.size() ; ++i) 21 | builder.append(array[i]); 22 | mongo::BSONArray::operator=(builder.arr()); 23 | } 24 | 25 | bool Contains(const T& value) const 26 | { 27 | std::vector array = *this; 28 | 29 | return (std::find(array.begin(), array.end(), value) != array.end()); 30 | } 31 | 32 | operator std::vector() const 33 | { 34 | std::vector elements; 35 | std::vector array; 36 | 37 | this->elems(elements); 38 | for (unsigned short i = 0 ; i < elements.size() ; ++i) 39 | { 40 | if (elements[i].ok()) 41 | { 42 | T val; 43 | 44 | elements[i].Val(val); 45 | array.push_back(val); 46 | } 47 | } 48 | return (array); 49 | } 50 | }; 51 | } 52 | 53 | #endif -------------------------------------------------------------------------------- /modules/mongodb/crails/mongodb/collection.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MONGODB_COLLECTION_HPP 2 | # define MONGODB_COLLECTION_HPP 3 | 4 | # include 5 | 6 | namespace MongoDB 7 | { 8 | class Database; 9 | 10 | class Collection 11 | { 12 | public: 13 | Collection(mongo::DBClientConnection& c, Database& db, const std::string& name) : db(db), connection(c), name(name) 14 | {} 15 | 16 | Database& get_database(void) { return (db); } 17 | unsigned int count(const mongo::Query& query = mongo::Query()); 18 | const std::string& get_name(void) const { return (name); } 19 | const std::string get_full_name(void) const; 20 | bool operator==(const std::string& name) const { return (this->name == name); } 21 | 22 | std::auto_ptr query(mongo::Query query = mongo::Query(), int n_to_return = 0, int n_to_skip = 0, mongo::BSONObj* fields_to_return = 0, int query_options = 0, int batch_size = 0); 23 | 24 | void find(std::vector& out, mongo::Query query = mongo::Query(), int n_to_return = 0, int n_to_skip = 0, mongo::BSONObj* fields_to_return = 0, int query_options = 0); 25 | 26 | void update(mongo::BSONObj object, mongo::Query query, bool upsert = false, bool multi = false); 27 | void insert(mongo::BSONObj object, unsigned int flags = 0); 28 | void remove(const mongo::Query& query, bool just_one = false); 29 | 30 | private: 31 | Database& db; 32 | mongo::DBClientConnection& connection; 33 | const std::string name; 34 | }; 35 | } 36 | 37 | #endif -------------------------------------------------------------------------------- /modules/mongodb/crails/mongodb/database.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MONGODB_DATABASE_HPP 2 | # define MONGODB_DATABASE_HPP 3 | 4 | # include 5 | # include "collection.hpp" 6 | 7 | # define MONGODB_GET_COLLECTION(database,collection) \ 8 | CRAILS_DATABASE(MongoDB,database)[collection] 9 | 10 | namespace MongoDB 11 | { 12 | class Database : public Crails::Databases::Db 13 | { 14 | public: 15 | typedef std::list Collections; 16 | 17 | static const std::string ClassType(void) { return ("mongodb"); } 18 | 19 | Database(Data settings); 20 | 21 | bool operator==(const std::string& name) const { return (this->name == name); } 22 | Collection& operator[](const std::string& name); 23 | void authenticate_with(const std::string& username, const std::string& password); 24 | const std::string& get_name(void) const { return (name); } 25 | Collections& get_collections(void) { return (collections); } 26 | const Collections& get_collections(void) const { return (collections); } 27 | void refresh_collections(void); 28 | void drop_all_collections(void); 29 | void drop_collection(const std::string& name); 30 | 31 | void connect(void); 32 | 33 | private: 34 | void initialize_mongo_client(); 35 | 36 | mongo::DBClientConnection connection; 37 | const std::string name; 38 | Collections collections; 39 | std::string hostname, username, password; 40 | unsigned short port; 41 | bool connected; 42 | }; 43 | } 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /modules/mongodb/crails/mongodb/exception.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CRAILS_MONGODB_EXCEPTION_HPP 2 | # define CRAILS_MONGODB_EXCEPTION_HPP 3 | 4 | # include 5 | # include 6 | 7 | namespace MongoDB 8 | { 9 | class Exception : public boost_ext::exception 10 | { 11 | public: 12 | Exception(const std::string& message) : message(message) 13 | { 14 | } 15 | 16 | const char* what(void) const throw() 17 | { 18 | return (message.c_str()); 19 | } 20 | 21 | private: 22 | std::string message; 23 | }; 24 | } 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /modules/mongodb/crails/session_store/mongodb.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MONGO_STORE_HPP 2 | # define MONGO_STORE_HPP 3 | 4 | # include "crails/cookie_data.hpp" 5 | # include "crails/http_response.hpp" 6 | # include "crails/session_store.hpp" 7 | 8 | # include 9 | 10 | namespace Crails 11 | { 12 | class MongoStore : public SessionStore 13 | { 14 | public: 15 | class SessionStore : public MongoDB::Model 16 | { 17 | public: 18 | static const std::string& CollectionName(void) { return (collection_name); } 19 | static const std::string& DatabaseName(void) { return (database_name); } 20 | 21 | MONGODB_MODEL(SessionStore) 22 | 23 | void set_fields(Data data); 24 | void get_fields(Data data); 25 | void save(void); 26 | 27 | static void Cleanup(void); 28 | 29 | static const std::string collection_name; 30 | static const std::string database_name; 31 | static const unsigned int session_expiration; 32 | }; 33 | 34 | MongoStore(); 35 | ~MongoStore(); 36 | 37 | void load(Data request_headers); 38 | void finalize(BuildingResponse& response); 39 | DynStruct& to_data(void) { return (session_content); } 40 | const DynStruct& to_data(void) const { return (session_content); } 41 | 42 | private: 43 | std::unique_ptr session; 44 | CookieData cookie; 45 | DynStruct session_content; 46 | }; 47 | } 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /modules/mongodb/scripts/lib/docker_mongodb_plugin.rb: -------------------------------------------------------------------------------- 1 | class CrailsDocker < CrailsDockerBase 2 | def crails_compile_files 3 | ["compile-mongo-cxx-driver.sh"] 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /modules/mongodb/scripts/modules/mongodb/install-session.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | $: << "#{ENV['CRAILS_SHARED_DIR']}/scripts/lib" 4 | 5 | require 'project_model' 6 | require 'cmakelists' 7 | 8 | project = ProjectModel.new 9 | base_directory = Dir.pwd 10 | source = ENV['CRAILS_SHARED_DIR'] + '/app_template/mongodb' 11 | 12 | project.base_directory source, base_directory do 13 | project.directory :config do 14 | project.file 'session_store.cpp' 15 | end 16 | end 17 | 18 | cmake = CMakeLists.new 19 | cmake.add_crails_module 'mongodb-session' 20 | 21 | guardfile = GuardfileEditor.new 22 | guardfile.add_task 'before_compile', < Collection::query(mongo::Query query, int n_to_return, int n_to_skip, mongo::BSONObj* fields_to_return, int query_options, int batch_size) 18 | { 19 | return (connection.query(get_full_name(), query, n_to_return, n_to_skip, fields_to_return, query_options, batch_size)); 20 | } 21 | 22 | void Collection::find(std::vector& out, mongo::Query query, int n_to_return, int n_to_skip, mongo::BSONObj* fields_to_return, int query_options) 23 | { 24 | connection.findN(out, get_full_name(), query, n_to_return, n_to_skip, fields_to_return, query_options); 25 | } 26 | 27 | void Collection::update(mongo::BSONObj object, mongo::Query query, bool upsert, bool multi) 28 | { 29 | connection.update(get_full_name(), query, object, upsert, multi); 30 | } 31 | 32 | void Collection::insert(mongo::BSONObj object, unsigned int flags) 33 | { 34 | connection.insert(get_full_name(), object, flags); 35 | } 36 | 37 | void Collection::remove(const mongo::Query& query, bool just_one) 38 | { 39 | connection.remove(get_full_name(), query, just_one); 40 | } -------------------------------------------------------------------------------- /modules/mongodb/src/criteria.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace MongoDB; 4 | using namespace std; 5 | 6 | CriteriaBase::CriteriaBase(Collection& collection, mongo::Query query) : collection(collection), 7 | query_options(0), batch_size(0), sort_order(0), fields_to_return(0), query(query) 8 | { 9 | } 10 | 11 | unsigned int CriteriaBase::count(void) 12 | { 13 | return collection.count(query); 14 | } 15 | 16 | void CriteriaBase::where(mongo::Query new_query) 17 | { 18 | mongo::BSONObjBuilder query_builder; 19 | 20 | query_builder.appendElements(query.getFilter()); 21 | query_builder.appendElements(new_query.getFilter()); 22 | query = mongo::Query(query_builder.obj()); 23 | } 24 | 25 | void CriteriaBase::sort_by(const string& key, char value) 26 | { 27 | sort_key = key; 28 | sort_order = value; 29 | } 30 | 31 | void CriteriaBase::remove(void) 32 | { 33 | collection.remove(query, false); 34 | } 35 | 36 | void CriteriaBase::remove_one(void) 37 | { 38 | collection.remove(query, true); 39 | } 40 | 41 | void CriteriaBase::ensure_result_fetched() 42 | { 43 | if (!results) 44 | fetch(); 45 | } 46 | 47 | void CriteriaBase::fetch() 48 | { 49 | typename std::auto_ptr results_auto_ptr; 50 | 51 | if (sort_order != 0) 52 | query = query.sort(sort_key, sort_order); 53 | results = collection.query(query, 54 | n_to_return, 55 | n_to_skip, 56 | fields_to_return, 57 | query_options, 58 | batch_size); 59 | } 60 | -------------------------------------------------------------------------------- /modules/odb/app/config/odb.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace ODB; 5 | 6 | const bool ODB::Transaction::use_session = false; 7 | 8 | const Database::Initializers Database::initializers = { 9 | { sqlite, &initialize_for_sqlite }, 10 | { pgsql, &initialize_for_postgresql }, 11 | { mysql, &initialize_for_mysql }, 12 | { oracle, &initialize_for_oracle } 13 | }; 14 | -------------------------------------------------------------------------------- /modules/odb/app/config/odb.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_ODB_HPP 2 | # define CONFIG_ODB_HPP 3 | 4 | // Enable schema versioning 5 | # pragma db model version(1,1) 6 | 7 | // Map your odb types here 8 | # pragma db map type("INTEGER\\[\\]") as("TEXT") to("(?)::INTEGER[]") from("(?)::TEXT") 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /modules/odb/app/docker/base/compile-odb.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -ex 2 | 3 | ODB_MAJOR_VERSION=2 4 | ODB_MINOR_VERSION=5 5 | ODB_PATCH_VERSION=0 6 | ODB_SHORT_VERSION="$ODB_MAJOR_VERSION.$ODB_MINOR_VERSION" 7 | ODB_VERSION="$ODB_MAJOR_VERSION.$ODB_MINOR_VERSION.$ODB_PATCH_VERSION-b.3" 8 | 9 | apt-get update 10 | apt-get install -y gcc-7-plugin-dev libpq-dev libsqlite3-dev 11 | 12 | CUTL_VERSION_MAJOR=1 13 | CUTL_VERSION_MINOR=11 14 | CUTL_VERSION_PATCH=0 15 | CUTL_VERSION="$CUTL_VERSION_MAJOR.$CUTL_VERSION_MINOR.$CUTL_VERSION_PATCH" 16 | 17 | wget http://www.codesynthesis.com/download/libcutl/$CUTL_VERSION_MAJOR.$CUTL_VERSION_MINOR/libcutl-$CUTL_VERSION.tar.gz 18 | tar -xvzf libcutl-$CUTL_VERSION.tar.gz 19 | cd libcutl-$CUTL_VERSION 20 | ./configure 21 | make 22 | make install 23 | cd .. 24 | 25 | for package_name in odb libodb libodb-pgsql libodb-sqlite; do 26 | # Use 2.5.0 pre-release for gcc-7 support 27 | wget https://codesynthesis.com/~boris/tmp/odb/pre-release/b.3/$package_name-$ODB_VERSION.tar.gz 28 | #wget http://www.codesynthesis.com/download/odb/$ODB_SHORT_VERSION/$package_name-$ODB_VERSION.tar.gz 29 | tar -xzvf $package_name-$ODB_VERSION.tar.gz 30 | cd $package_name-$ODB_VERSION 31 | ./configure 32 | make 33 | make install 34 | cd .. 35 | done 36 | -------------------------------------------------------------------------------- /modules/odb/app/tasks/odb_migrate/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | file(GLOB task_files 4 | *.cpp 5 | *.cxx) 6 | 7 | add_executable(odb_migrate ${task_files}) 8 | 9 | target_link_libraries(odb_migrate ${dependencies}) 10 | 11 | set_target_properties(odb_migrate PROPERTIES OUTPUT_NAME "task") 12 | -------------------------------------------------------------------------------- /modules/odb/app/tasks/odb_migrate/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | int help(char* arg_command) 7 | { 8 | cout << "Usage: " << arg_command << " [options] database_key" << endl; 9 | cout << "Options:" << endl; 10 | cout << "\t-c: create the database before performing the migration" << endl; 11 | cout << "\t-d: drop the schema instead of performing a migration" << endl; 12 | return -1; 13 | } 14 | 15 | void create_database(const std::string& database_name) 16 | { 17 | const auto& settings = Crails::Databases::settings.at(Crails::environment).at(database_name); 18 | 19 | // The second and third parameters are the user and password for the database, 20 | // If left empty, it uses the identity specified in the database settings. 21 | // Make sure to use the credentials of a user which can create users and databases. 22 | ODB::Database::create_from_settings(settings, "", ""); 23 | } 24 | 25 | int main(int argc, char** argv) 26 | { 27 | if (argc < 2) 28 | return help(argv[0]); 29 | else 30 | { 31 | string database_name = argv[argc - 1]; 32 | string option = argc > 2 ? string(argv[1]) : string(""); 33 | 34 | if (option == "-c") 35 | create_database(database_name); 36 | { 37 | ODB::Database& database = CRAILS_DATABASE(ODB, database_name); 38 | 39 | if (option == "-d") 40 | database.drop(); 41 | else 42 | database.migrate(); 43 | } 44 | } 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /modules/odb/crails/odb/any.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ODB_ANY_HPP 2 | # define ODB_ANY_HPP 3 | 4 | # include 5 | # include 6 | 7 | namespace ODB 8 | { 9 | template 10 | std::string array_to_string(const ARRAY& array, const std::string& sql_type) 11 | { 12 | std::stringstream stream; 13 | 14 | stream << "'{"; 15 | for (auto it = array.begin() ; it != array.end() ; ++it) 16 | { 17 | if (it != array.begin()) 18 | stream << ','; 19 | stream << *it; 20 | } 21 | stream << "}'::" << sql_type << "[]"; 22 | return stream.str(); 23 | } 24 | 25 | template 26 | std::string any(const ARRAY& array, const std::string& sql_type) 27 | { 28 | return "ANY(" + array_to_string(array, sql_type) + ')'; 29 | } 30 | } 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /modules/odb/crails/odb/controller.hpp: -------------------------------------------------------------------------------- 1 | #ifndef DATABASE_CONTROLLER_HPP 2 | # define DATABASE_CONTROLLER_HPP 3 | 4 | # include 5 | # include "connection.hpp" 6 | 7 | namespace ODB 8 | { 9 | class Controller : public Crails::Controller 10 | { 11 | protected: 12 | ODB::Connection database; 13 | 14 | public: 15 | Controller(Crails::Params& params); 16 | 17 | void finalize(); 18 | }; 19 | } 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /modules/odb/crails/odb/database_settings.hpp: -------------------------------------------------------------------------------- 1 | #ifndef DB_DATABASE_SETTINGS_HPP 2 | # define DB_DATABASE_SETTINGS_HPP 3 | 4 | # include 5 | 6 | namespace ODB 7 | { 8 | Crails::Databases::DatabaseSettings get_database_settings_for(const std::string& name); 9 | } 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /modules/odb/crails/odb/exception.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ODB_EXCEPTION_HPP 2 | # define ODB_EXCEPTION_HPP 3 | 4 | # include 5 | # include 6 | # include 7 | 8 | namespace ODB 9 | { 10 | template 11 | void throw_exception(const MODEL& model, const std::string& what) 12 | { 13 | std::stringstream stream; 14 | 15 | stream << "object(" << model.get_id() << "): "; 16 | stream << what; 17 | throw boost_ext::runtime_error(stream.str().c_str()); 18 | } 19 | } 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /modules/odb/crails/odb/id_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ODB_ID_TYPE_HPP 2 | # define ODB_ID_TYPE_HPP 3 | 4 | # ifndef ODB_ID_TYPE 5 | # define ODB_ID_TYPE unsigned long 6 | # define ODB_NULL_ID 0 7 | # endif 8 | 9 | namespace ODB 10 | { 11 | typedef ODB_ID_TYPE id_type; 12 | } 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /modules/odb/crails/odb/migration.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MY_MIGRATION_HPP 2 | # define MY_MIGRATION_HPP 3 | 4 | # include 5 | # include 6 | # include 7 | 8 | # ifndef ODB_COMPILER 9 | # include 10 | # else 11 | namespace ODB { class Database; } 12 | # endif 13 | 14 | namespace ODB 15 | { 16 | typedef std::function MigrateFunction; 17 | 18 | struct Migration 19 | { 20 | std::string name; 21 | odb::schema_version version; 22 | std::function runner; 23 | }; 24 | 25 | struct Migrations 26 | { 27 | Migrations(); 28 | 29 | bool run_for_version(ODB::Database& db, odb::schema_version version) const; 30 | std::list list; 31 | 32 | operator MigrateFunction() const 33 | { 34 | return std::bind(&ODB::Migrations::run_for_version, this, std::placeholders::_1, std::placeholders::_2); 35 | } 36 | }; 37 | } 38 | 39 | # define ADD_MIGRATION(name, version, body) \ 40 | ODB::Migration name = { #name, version, [](ODB::Database& database) -> bool body }; 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /modules/odb/crails/odb/model.hpp: -------------------------------------------------------------------------------- 1 | #ifndef DB_MODEL_HPP 2 | # define DB_MODEL_HPP 3 | 4 | # include "model/timestamps.hpp" 5 | # include "config/odb.hpp" 6 | 7 | namespace ODB 8 | { 9 | typedef ModelTimestamps Model; 10 | } 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /modules/odb/crails/odb/model/soft_delete.hpp: -------------------------------------------------------------------------------- 1 | #ifndef DB_MODEL_SOFT_DELETE_HPP 2 | # define DB_MODEL_SOFT_DELETE_HPP 3 | 4 | # include "base.hpp" 5 | 6 | namespace ODB 7 | { 8 | # pragma db object abstract 9 | class ModelSoftDelete : public ModelBase 10 | { 11 | friend class odb::access; 12 | typedef ModelBase BaseType; 13 | public: 14 | virtual bool with_soft_delete() const { return false; } 15 | bool is_deleted() const { return deleted; } 16 | 17 | void save(odb::database&); 18 | void destroy(odb::database&); 19 | 20 | private: 21 | #pragma db default(false) 22 | bool deleted; 23 | }; 24 | } 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /modules/odb/crails/odb/model/timestamps.hpp: -------------------------------------------------------------------------------- 1 | #ifndef DB_MODEL_TIMESTAMPS_HPP 2 | # define DB_MODEL_TIMESTAMPS_HPP 3 | 4 | # include "soft_delete.hpp" 5 | # include 6 | 7 | namespace ODB 8 | { 9 | #pragma db object abstract 10 | class ModelTimestamps : public ModelSoftDelete 11 | { 12 | friend class odb::access; 13 | typedef ModelSoftDelete BaseType; 14 | public: 15 | std::time_t get_created_at() const { return created_at; } 16 | std::time_t get_udpated_at() const { return updated_at; } 17 | void update_timestamps(); 18 | 19 | void save(odb::database&); 20 | void destroy(odb::database&); 21 | 22 | private: 23 | #pragma db null 24 | std::time_t created_at; 25 | #pragma db null 26 | std::time_t updated_at; 27 | }; 28 | } 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /modules/odb/crails/odb/traits.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MY_TRAITS_HPP 2 | # define MY_TRAITS_HPP 3 | 4 | # include "traits/datatree.hpp" 5 | # include "traits/vector_id.hpp" 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /modules/odb/crails/odb/traits/datatree.hpp: -------------------------------------------------------------------------------- 1 | #ifndef DATATREE_TRAITS_HPP 2 | #define DATATREE_TRAITS_HPP 3 | 4 | #include // std::memcpy 5 | #include 6 | #include 7 | #include 8 | 9 | namespace odb 10 | { 11 | namespace pgsql 12 | { 13 | template <> 14 | class value_traits 15 | { 16 | public: 17 | typedef DataTree value_type; 18 | typedef value_type query_type; 19 | typedef details::buffer image_type; 20 | 21 | static void 22 | set_value (DataTree& tree, 23 | const details::buffer& b, 24 | std::size_t n, 25 | bool is_null) 26 | { 27 | if (!is_null && n > 0) 28 | { 29 | std::string v; 30 | v.assign (b.data (), n); 31 | try { 32 | tree.from_json(v); 33 | } catch (const std::exception& e) { 34 | Crails::logger << "[ODB][DataTree traits] could not unserialize: " << e.what() << Crails::Logger::endl; 35 | } 36 | } 37 | else 38 | tree.as_data().destroy(); 39 | } 40 | 41 | static void 42 | set_image (details::buffer& b, 43 | std::size_t& n, 44 | bool& is_null, 45 | const DataTree& tree) 46 | { 47 | std::string v = tree.to_json(); 48 | 49 | is_null = false; 50 | n = v.size (); 51 | 52 | if (n > b.capacity ()) 53 | b.capacity (n); 54 | 55 | std::memcpy (b.data (), v.c_str (), n); 56 | } 57 | }; 58 | } 59 | } 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /modules/odb/crails/odb/transaction.hpp: -------------------------------------------------------------------------------- 1 | #ifndef DB_TRANSACTION_HPP 2 | # define DB_TRANSACTION_HPP 3 | 4 | # include 5 | # include 6 | 7 | namespace odb 8 | { 9 | class transaction; 10 | class session; 11 | class database; 12 | } 13 | 14 | namespace ODB 15 | { 16 | struct Transaction 17 | { 18 | Transaction(); 19 | ~Transaction(); 20 | 21 | std::string get_database_name() const { return database_name; } 22 | odb::database& get_database(); 23 | 24 | void require(const std::string& name); 25 | void start(const std::string& name, odb::database&); 26 | void commit(); 27 | void rollback(); 28 | 29 | private: 30 | void cleanup(); 31 | 32 | static const bool use_session; 33 | 34 | std::string database_name; 35 | std::unique_ptr odb_transaction; 36 | std::unique_ptr odb_session; 37 | odb::database* odb_database; 38 | }; 39 | } 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /modules/odb/scripts/lib/docker_odb_plugin.rb: -------------------------------------------------------------------------------- 1 | class CrailsDocker < CrailsDockerBase 2 | def crails_compile_files 3 | ["compile-odb.sh"] 4 | end 5 | 6 | def system_dependencies 7 | ["libpq-dev"] 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /modules/odb/src/connection.cpp: -------------------------------------------------------------------------------- 1 | #include "../crails/odb/connection.hpp" 2 | #include 3 | 4 | using namespace std; 5 | 6 | thread_local safe_ptr ODB::Connection::instance; 7 | 8 | ODB::Connection::Connection() 9 | { 10 | if (instance) 11 | throw runtime_error("only one instance of ODB::Connection allowed per thread"); 12 | instance = shared_ptr(this, [](ODB::Connection*) {}); 13 | } 14 | 15 | ODB::Connection::~Connection() 16 | { 17 | rollback(); 18 | instance.reset(); 19 | } 20 | 21 | void ODB::Connection::commit() 22 | { 23 | Crails::logger << Crails::Logger::Info << "Transaction commit. Database time: " << time << 's' << Crails::Logger::endl; 24 | Utils::Timer timer; 25 | transaction.commit(); 26 | Crails::logger << Crails::Logger::Info << "Transaction committed in " << timer.GetElapsedSeconds() << Crails::Logger::endl; 27 | time = 0.f; 28 | } 29 | 30 | void ODB::Connection::rollback() 31 | { 32 | transaction.rollback(); 33 | time = 0.f; 34 | } 35 | -------------------------------------------------------------------------------- /modules/odb/src/controller.cpp: -------------------------------------------------------------------------------- 1 | #include "../crails/odb/controller.hpp" 2 | 3 | using namespace Crails; 4 | 5 | ODB::Controller::Controller(Crails::Params& params) : Crails::Controller(params) 6 | { 7 | } 8 | 9 | void ODB::Controller::finalize() 10 | { 11 | if (!(response["status"].exists()) || (response["status"].as() == Server::HttpCodes::ok)) 12 | database.commit(); 13 | } 14 | -------------------------------------------------------------------------------- /modules/odb/src/database_settings.cpp: -------------------------------------------------------------------------------- 1 | #include "../crails/odb/database_settings.hpp" 2 | #include 3 | 4 | using namespace Crails; 5 | 6 | extern const std::string default_configuration_name = "odb"; 7 | 8 | Databases::DatabaseSettings ODB::get_database_settings_for(const std::string& name) 9 | { 10 | const auto& settings = Databases::settings 11 | .at(Crails::environment) 12 | .at(default_configuration_name); 13 | 14 | return { 15 | { "type", settings.at("type") }, 16 | { "host", settings.at("host") }, 17 | { "name", name }, 18 | { "user", settings.at("user") }, 19 | { "password", settings.at("password") }, 20 | { "port", settings.at("port") } 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /modules/odb/src/migration.cpp: -------------------------------------------------------------------------------- 1 | #include "../crails/odb/migration.hpp" 2 | 3 | using namespace ODB; 4 | using namespace std; 5 | 6 | bool Migrations::run_for_version(ODB::Database& db, odb::schema_version version) const 7 | { 8 | for (auto migration : list) 9 | { 10 | if (migration.version == version) 11 | { 12 | cout << "+ " << migration.name << endl; 13 | if (!(migration.runner(db))) 14 | { 15 | cout << "/!\\ Migration failed to run" << endl; 16 | return false; 17 | } 18 | } 19 | } 20 | return true; 21 | } 22 | -------------------------------------------------------------------------------- /modules/odb/src/model/base.cpp: -------------------------------------------------------------------------------- 1 | #include "../../crails/odb/model/base.hpp" 2 | 3 | using namespace std; 4 | 5 | std::string ODB::ModelBase::get_database_name() const 6 | { 7 | return "default"; 8 | } 9 | 10 | void ODB::ModelBase::save(odb::database& db) 11 | { 12 | if (id == 0) 13 | odb_persist(db); 14 | else 15 | odb_update(db); 16 | } 17 | 18 | void ODB::ModelBase::destroy(odb::database& db) 19 | { 20 | if (id != 0) 21 | odb_erase(db); 22 | erased = true; 23 | } 24 | -------------------------------------------------------------------------------- /modules/odb/src/model/soft_delete.cpp: -------------------------------------------------------------------------------- 1 | #include "../../crails/odb/model/soft_delete.hpp" 2 | 3 | using namespace std; 4 | 5 | void ODB::ModelSoftDelete::save(odb::database& db) 6 | { 7 | deleted = false; 8 | BaseType::save(db); 9 | } 10 | 11 | void ODB::ModelSoftDelete::destroy(odb::database& db) 12 | { 13 | if (with_soft_delete() && get_id() != 0) 14 | { 15 | deleted = true; 16 | BaseType::save(db); 17 | } 18 | else 19 | BaseType::destroy(db); 20 | } 21 | -------------------------------------------------------------------------------- /modules/odb/src/model/timestamps.cpp: -------------------------------------------------------------------------------- 1 | #include "../../crails/odb/model/timestamps.hpp" 2 | #include 3 | 4 | using namespace std; 5 | 6 | void ODB::ModelTimestamps::save(odb::database& db) 7 | { 8 | update_timestamps(); 9 | BaseType::save(db); 10 | } 11 | 12 | void ODB::ModelTimestamps::destroy(odb::database& db) 13 | { 14 | update_timestamps(); 15 | BaseType::destroy(db); 16 | } 17 | 18 | void ODB::ModelTimestamps::update_timestamps() 19 | { 20 | auto now = chrono::system_clock::now(); 21 | 22 | updated_at = chrono::system_clock::to_time_t(now); 23 | if (get_id() == 0) 24 | created_at = updated_at; 25 | } 26 | -------------------------------------------------------------------------------- /modules/proxy/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(crails-proxy) 4 | 5 | include_directories(.) 6 | 7 | file(GLOB crails_proxy src/*.cpp) 8 | file(GLOB headers_crails_proxy crails/request_parsers/proxy.hpp) 9 | file(GLOB template_crails_proxy app/config/proxy.json) 10 | file(GLOB scripts_crails_proxy scripts/modules/proxy/*.rb) 11 | 12 | add_library(crails-proxy${crails-suffix} SHARED ${crails_proxy}) 13 | 14 | install(FILES ${headers_crails_proxy} DESTINATION include/crails/request_parsers) 15 | install(FILES ${template_crails_proxy} DESTINATION share/crails/app_template/proxy) 16 | install(FILES ${scripts_crails_proxy} DESTINATION share/crails/scripts/modules/proxy) 17 | install(TARGETS crails-proxy${crails-suffix} LIBRARY DESTINATION lib) 18 | -------------------------------------------------------------------------------- /modules/proxy/app/config/proxy.json: -------------------------------------------------------------------------------- 1 | { 2 | "default_mode": "proxy", 3 | "rules": [] 4 | } 5 | -------------------------------------------------------------------------------- /modules/proxy/crails/request_parsers/proxy.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PROXY_REQUEST_HANDLER_HPP 2 | # define PROXY_REQUEST_HANDLER_HPP 3 | 4 | # include 5 | # include 6 | 7 | namespace Crails 8 | { 9 | class ProxyRequestHandler : public BodyParser 10 | { 11 | public: 12 | enum Mode 13 | { 14 | Redirect302, 15 | Proxy 16 | }; 17 | 18 | struct Rule 19 | { 20 | bool operator==(const std::string& uri) const { return uri.find(matcher) != std::string::npos; } 21 | 22 | std::string matcher; 23 | std::string target_url; 24 | unsigned short target_port; 25 | Mode mode; 26 | }; 27 | 28 | typedef std::vector Rules; 29 | 30 | ProxyRequestHandler(); 31 | 32 | void operator()(const HttpServer::request& request, BuildingResponse& out, Params& params, std::function); 33 | 34 | private: 35 | void body_received(const HttpServer::request& request, BuildingResponse& out, Params& params, const std::string& body); 36 | void execute_rule(const Rule& rule, const HttpServer::request&, const std::string& body, BuildingResponse&); 37 | Mode get_mode_from_data(Data) const; 38 | static std::string get_proxyfied_url(const Rule& rule, const std::string& uri); 39 | 40 | static thread_local http::client client; 41 | Mode default_mode; 42 | Rules rules; 43 | }; 44 | } 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /modules/proxy/scripts/modules/proxy/install.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | $: << "#{ENV['CRAILS_SHARED_DIR']}/scripts/lib" 4 | 5 | require 'project_model' 6 | require 'cmakelists' 7 | require 'maincpp' 8 | 9 | project = ProjectModel.new 10 | base_directory = Dir.pwd 11 | source = ENV['CRAILS_SHARED_DIR'] + '/app_template/proxy' 12 | 13 | project.base_directory source, base_directory do 14 | project.directory :config do 15 | project.file 'proxy.json' 16 | end 17 | end 18 | 19 | cmake = CMakeLists.new 20 | cmake.add_crails_module 'proxy' 21 | cmake.write 22 | -------------------------------------------------------------------------------- /modules/selenium/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(crails-selenium) 4 | 5 | include_directories(.) 6 | 7 | file(GLOB crails_selenium src/*.cpp) 8 | file(GLOB headers_crails_selenium crails/tests/*.hpp) 9 | file(GLOB scripts_crails_selenium scripts/modules/selenium/*.rb) 10 | 11 | add_library(crails-selenium${crails-suffix} SHARED ${crails_selenium}) 12 | 13 | install(FILES ${headers_crails_selenium} DESTINATION include/crails/tests) 14 | install(FILES ${scripts_crails_selenium} DESTINATION share/crails/scripts/modules/selenium) 15 | install(TARGETS crails-selenium${crails-suffix} LIBRARY DESTINATION lib) 16 | -------------------------------------------------------------------------------- /modules/selenium/crails/tests/background_server.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CRAILS_TESTS_BACKGROUND_SERVER_HPP 2 | # define CRAILS_TESTS_BACKGROUND_SERVER_HPP 3 | 4 | # include 5 | 6 | namespace Crails 7 | { 8 | namespace Tests 9 | { 10 | class BackgroundServer 11 | { 12 | static pid_t pid; 13 | public: 14 | static void initialize(); 15 | static void finalize(); 16 | 17 | private: 18 | static void start_server(); 19 | }; 20 | } 21 | } 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /modules/selenium/crails/tests/selenium_helper.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CRAILS_TESTS_SELENIUM_HELPER_HPP 2 | # define CRAILS_TESTS_SELENIUM_HELPER_HPP 3 | 4 | # include 5 | # include 6 | 7 | namespace Crails 8 | { 9 | namespace Tests 10 | { 11 | struct SeleniumHelper : public Crails::Tests::Helper 12 | { 13 | std::unique_ptr page; 14 | std::string browser = "firefox"; 15 | 16 | SeleniumHelper(const std::string& name) : Helper(name) 17 | { 18 | before([this]() { 19 | page.reset(new SeleniumDriver); 20 | page->use_browser(browser); 21 | }); 22 | 23 | after([this]() { 24 | page.reset(nullptr); 25 | }); 26 | } 27 | }; 28 | } 29 | } 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /modules/selenium/crails/tests/selenium_server.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CRAILS_TESTS_SELENIUM_SERVER_HPP 2 | # define CRAILS_TESTS_SELENIUM_SERVER_HPP 3 | 4 | # include 5 | 6 | namespace Crails 7 | { 8 | namespace Tests 9 | { 10 | class SeleniumServer 11 | { 12 | static std::unique_ptr instance; 13 | 14 | public: 15 | static void initialize() 16 | { 17 | instance.reset(new SeleniumServer); 18 | } 19 | 20 | static void finalize() 21 | { 22 | instance.reset(nullptr); 23 | } 24 | 25 | ~SeleniumServer() 26 | { 27 | } 28 | 29 | private: 30 | SeleniumServer(); 31 | 32 | std::unique_ptr process; 33 | }; 34 | } 35 | } 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /modules/selenium/scripts/modules/selenium/install.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | $: << "#{ENV['CRAILS_SHARED_DIR']}/scripts/lib" 4 | 5 | require 'net/http' 6 | require 'cmakelists' 7 | 8 | selenium_minor_version = "3.14" 9 | selenium_version = selenium_minor_version + ".0" 10 | selenium_package_name = "selenium-server-standalone" 11 | 12 | Net::HTTP.start "selenium-release.storage.googleapis.com", 443, use_ssl: true do |http| 13 | response = http.get "#{selenium_minor_version}/#{selenium_package_name}-#{selenium_version}.jar" 14 | open "spec/#{selenium_package_name}.jar", 'w' do |file| 15 | file.write response.body 16 | end 17 | end 18 | 19 | cmake = CMakeLists.new 20 | cmake.add_dependency 'curl', 'tests_dependencies' # dependency of webdriverxx 21 | cmake.add_crails_module 'selenium', 'tests_dependencies' 22 | cmake.write 23 | 24 | puts "/!\\ This module depends on libcurl and webdriverxx (https://github.com/durdyev/webdriverxx)" 25 | -------------------------------------------------------------------------------- /modules/selenium/src/background_server.cpp: -------------------------------------------------------------------------------- 1 | #include "crails/tests/background_server.hpp" 2 | #include "crails/server.hpp" 3 | #include "crails/router.hpp" 4 | #include 5 | #include 6 | 7 | using namespace Crails::Tests; 8 | using namespace std; 9 | 10 | pid_t Crails::Tests::BackgroundServer::pid = 0; 11 | 12 | void BackgroundServer::initialize() 13 | { 14 | pid = fork(); 15 | if (pid == 0) 16 | start_server(); 17 | } 18 | 19 | void BackgroundServer::finalize() 20 | { 21 | if (pid != 0) 22 | kill(pid, SIGINT); 23 | } 24 | 25 | void BackgroundServer::start_server() 26 | { 27 | const char* argv[3]; 28 | 29 | argv[0] = ""; 30 | argv[1] = "-p"; 31 | argv[2] = "4445"; 32 | Crails::Router::singleton::Finalize(); // will be re-initialized by Launch 33 | Crails::Server::Launch(3, argv); 34 | exit(EXIT_SUCCESS); 35 | } 36 | -------------------------------------------------------------------------------- /modules/selenium/src/selenium_server.cpp: -------------------------------------------------------------------------------- 1 | #include "crails/tests/selenium_server.hpp" 2 | #include "crails/getenv.hpp" 3 | #include 4 | 5 | using namespace Crails::Tests; 6 | using namespace std; 7 | 8 | unique_ptr SeleniumServer::instance; 9 | 10 | SeleniumServer::SeleniumServer() 11 | { 12 | boost::system::error_code ec; 13 | string java_path = Crails::getenv("JAVA_PATH", "/usr/bin/java"); 14 | string server_path = Crails::getenv("SELENIUM_STANDALONE_SERVER_PATH", 15 | boost::filesystem::current_path().string() + "/spec/selenium-server-standalone.jar" 16 | ); 17 | 18 | boost::filesystem::canonical(java_path, ec); 19 | if (ec != boost::system::errc::success) 20 | throw std::runtime_error(string("java jre not found at " + java_path + " (use JAVA_PATH environment variable)")); 21 | boost::filesystem::canonical(server_path, ec); 22 | if (ec != boost::system::errc::success) 23 | throw std::runtime_error(string("selenium standalone server jar not found at " + server_path + " (use SELENIUM_STANDALONE_SERVER_PATH environment variable)")); 24 | 25 | process.reset( 26 | new boost::process::child( 27 | java_path + " -jar " + server_path, 28 | boost::process::std_in.close(), 29 | boost::process::std_out > boost::process::null, 30 | boost::process::std_err > boost::process::null 31 | ) 32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /modules/sentry/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(crails-sentry) 4 | 5 | include_directories(.) 6 | 7 | file(GLOB crails_sentry src/sentry.cpp) 8 | file(GLOB scripts_sentry_module scripts/modules/sentry/*.rb) 9 | file(GLOB_RECURSE sentry_app_template app/*) 10 | 11 | add_library(crails-sentry${crails-suffix} SHARED ${crails_sentry}) 12 | 13 | install(DIRECTORY crails DESTINATION include) 14 | install(FILES ${scripts_sentry_module} DESTINATION share/crails/scripts/modules/sentry) 15 | install(FILES ${sentry_app_template} DESTINATION share/crails/app_template/sentry) 16 | install(TARGETS crails-sentry${crails-suffix} LIBRARY DESTINATION lib) 17 | -------------------------------------------------------------------------------- /modules/sentry/app/config/sentry.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | thread_local Sentry sentry; 7 | 8 | const string Sentry::project_id = Crails::getenv("SENTRY_PROJECT_ID"); 9 | const string Sentry::sentry_key = Crails::getenv("SENTRY_KEY"); 10 | const string Sentry::sentry_secret = Crails::getenv("SENTRY_SECRET"); 11 | const string Sentry::server_url = Crails::getenv("SENTRY_PRIVATE_URL"); 12 | const string Sentry::server_protocol = Crails::getenv("SENTRY_PROTOCOL", "http"); 13 | -------------------------------------------------------------------------------- /modules/sentry/crails/sentry.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SENTRY_HPP 2 | # define SENTRY_HPP 3 | 4 | # include 5 | # include 6 | # include 7 | 8 | class Sentry 9 | { 10 | static const std::string sentry_key, 11 | sentry_secret, 12 | project_id, 13 | server_url, 14 | server_protocol; 15 | public: 16 | Sentry(); 17 | 18 | void capture_exception(Data, const std::exception&); 19 | 20 | private: 21 | void set_message_context(Data); 22 | void set_message_request(Data message, Data params); 23 | void initialize_exception_message(Data message, Data params, const std::exception&); 24 | void initialize_backtrace(Data, const boost_ext::backtrace&); 25 | 26 | void send_message(Data); 27 | static std::string get_server_url(); 28 | 29 | boost::network::http::client http; 30 | }; 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /modules/sentry/scripts/modules/sentry/install.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | $: << "#{ENV['CRAILS_SHARED_DIR']}/scripts/lib" 4 | 5 | require 'project_model' 6 | require 'cmakelists' 7 | require 'maincpp' 8 | 9 | project = ProjectModel.new 10 | base_directory = Dir.pwd 11 | source = ENV['CRAILS_SHARED_DIR'] + '/app_template/sentry' 12 | 13 | project.base_directory source, base_directory do 14 | project.directory :config do 15 | project.file 'sentry.cpp' 16 | end 17 | end 18 | 19 | cmake = CMakeLists.new 20 | cmake.add_crails_module 'sentry' 21 | cmake.write 22 | -------------------------------------------------------------------------------- /modules/sidekic/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(crails-sidekic) 4 | 5 | file(GLOB crails_sidekic src/*.cpp) 6 | file(GLOB headers_crails_sidekic crails/*.hpp) 7 | file(GLOB scripts_sidekic_module scripts/modules/sidekic/*.rb) 8 | file(GLOB_RECURSE sidekic_app_template app/*) 9 | 10 | add_library(crails-sidekic${crails-suffix} SHARED ${crails_sidekic}) 11 | install(FILES ${headers_crails_sidekic} DESTINATION include/crails) 12 | install(FILES ${scripts_sidekic_module} DESTINATION share/crails/scripts/modules/sidekic) 13 | install(FILES ${sidekic_app_template} DESTINATION share/crails/app_template/sidekic) 14 | install(TARGETS crails-sidekic${crails-suffix} LIBRARY DESTINATION lib) 15 | 16 | -------------------------------------------------------------------------------- /modules/sidekic/app/config/sidekic.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | const string Sidekic::tasks_path = boost::filesystem::current_path().string() + "/.pending_tasks"; 7 | -------------------------------------------------------------------------------- /modules/sidekic/app/tasks/sidekic/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | file(GLOB task_files 4 | sidetasks/*.cpp 5 | *.cpp 6 | *.cxx) 7 | 8 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DTHREAD_POOL_SIZE=2") 9 | 10 | add_executable(sidekic ${task_files}) 11 | 12 | target_link_libraries(sidekic ${dependencies}) 13 | 14 | set_target_properties(sidekic PROPERTIES OUTPUT_NAME "task") 15 | -------------------------------------------------------------------------------- /modules/sidekic/app/tasks/sidekic/sidetasks.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | using namespace Crails; 6 | 7 | // Your tasks go here 8 | map > sidetasks = { 9 | }; 10 | 11 | -------------------------------------------------------------------------------- /modules/sidekic/crails/sidekic.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SIDEKIC_HPP 2 | # define SIDEKIC_HPP 3 | 4 | # include 5 | 6 | struct Sidekic 7 | { 8 | static const std::string tasks_path; 9 | static std::string async_task(const std::string& name, Data params); 10 | static std::string schedule_task(std::time_t timestamp, const std::string& name, Data params); 11 | }; 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /modules/sidekic/scripts/modules/sidekic/install.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | $: << "#{ENV['CRAILS_SHARED_DIR']}/scripts/lib" 4 | 5 | require 'project_model' 6 | require 'cmakelists' 7 | require 'maincpp' 8 | 9 | project = ProjectModel.new 10 | base_directory = Dir.pwd 11 | source = ENV['CRAILS_SHARED_DIR'] + '/app_template/sidekic' 12 | 13 | project.base_directory source, base_directory do 14 | project.directory :config do 15 | project.file "sidekic.cpp" 16 | end 17 | 18 | project.directory :tasks do 19 | project.directory :sidekic do 20 | project.directory :sidetasks do end 21 | project.file "CMakeLists.txt" 22 | project.file "main.cpp" 23 | project.file "sidetasks.cpp" 24 | project.file "ctpl.h" 25 | end 26 | end 27 | end 28 | 29 | cmake = CMakeLists.new 30 | cmake.add_crails_module "sidekic" 31 | cmake.add_crails_task "sidekic" 32 | cmake.write 33 | -------------------------------------------------------------------------------- /modules/sidekic/src/sidekic.cpp: -------------------------------------------------------------------------------- 1 | #include "../crails/sidekic.hpp" 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | using namespace Crails; 8 | 9 | std::string Sidekic::async_task(const string& name, Data params) 10 | { 11 | if (Crails::environment == "test") return "dummy-async-task"; 12 | string uid = generate_random_string("abcdefghijklmnopqrstwxyz0123456789", 10); 13 | string filename = tasks_path + '/' + uid; 14 | ofstream file(filename.c_str()); 15 | 16 | if (file.is_open()) 17 | { 18 | params["sidekic"]["task_uid"] = uid; 19 | params["sidekic"]["type"] = name; 20 | file << params.to_json(); 21 | file.close(); 22 | } 23 | else 24 | throw boost_ext::runtime_error("sidekic cannot create file " + filename); 25 | return uid; 26 | } 27 | 28 | std::string Sidekic::schedule_task(time_t timestamp, const string& name, Data params) 29 | { 30 | params["sidekic"]["run_at"] = timestamp; 31 | return async_task(name, params); 32 | } 33 | 34 | -------------------------------------------------------------------------------- /modules/signin/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(crails-signin) 4 | 5 | include_directories(.) 6 | 7 | file(GLOB_RECURSE crails_signin src/*.cpp) 8 | file(GLOB headers_crails_signin crails/signin/*.hpp) 9 | file(GLOB headers_crails_front crails/front/*.hpp) 10 | file(GLOB scripts_signin_module scripts/modules/signin/*.rb) 11 | file(GLOB signin_templates app/config/signin.cpp) 12 | 13 | add_library(crails-signin${crails-suffix} SHARED ${crails_signin}) 14 | install(FILES ${headers_crails_signin} DESTINATION include/crails/signin) 15 | install(FILES ${headers_crails_front} DESTINATION include/crails/front) 16 | install(FILES ${scripts_signin_module} DESTINATION share/crails/scripts/modules/signin) 17 | install(FILES ${signin_templates} DESTINATION share/crails/app_template/signin) 18 | install(TARGETS crails-signin${crails-suffix} LIBRARY DESTINATION lib) 19 | -------------------------------------------------------------------------------- /modules/signin/app/config/signin.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | namespace Crails 6 | { 7 | const time_t AuthenticableModel::session_duration = 60 * 60 * 24; 8 | } 9 | -------------------------------------------------------------------------------- /modules/signin/crails/signin/auth_controller.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SIGNIN_AUTH_CONTROLLER_HPP 2 | # define SIGNIN_AUTH_CONTROLLER_HPP 3 | 4 | # include 5 | # include 6 | 7 | namespace Crails 8 | { 9 | template 10 | class AuthController : public SUPER 11 | { 12 | public: 13 | AuthController(Crails::Params& params) : SUPER(params), user_session(SUPER::session) 14 | { 15 | } 16 | 17 | void initialize() 18 | { 19 | SUPER::initialize(); 20 | initialize_required_user(); 21 | } 22 | 23 | virtual bool require_authentified_user() const { return false; } 24 | 25 | void initialize_required_user() 26 | { 27 | if (require_authentified_user()) 28 | initialize_current_user(); 29 | } 30 | 31 | protected: 32 | bool initialize_current_user() 33 | { 34 | if (user_session.get_current_user() == nullptr) 35 | SUPER::respond_with(SUPER::ResponseStatus::unauthorized); 36 | return true; 37 | } 38 | 39 | Session user_session; 40 | }; 41 | } 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /modules/signin/crails/signin/model.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CRAILS_SIGNIN_MODEL_HPP 2 | # define CRAILS_SIGNIN_MODEL_HPP 3 | 4 | # include 5 | # include 6 | 7 | namespace Crails 8 | { 9 | #pragma db object abstract 10 | class AuthenticableModel 11 | { 12 | public: 13 | static const std::time_t session_duration; 14 | 15 | const std::string& get_authentication_token() const { return authentication_token; } 16 | std::time_t get_sign_in_at() const { return sign_in_at; } 17 | 18 | void set_authentication_token(const std::string& v) { authentication_token = v; } 19 | void set_sign_in_at(std::time_t v) { sign_in_at = v; } 20 | 21 | void generate_authentication_token(); 22 | std::time_t get_token_expires_in() const; 23 | 24 | private: 25 | std::string authentication_token; 26 | std::time_t sign_in_at = 0; 27 | }; 28 | } 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /modules/signin/scripts/modules/signin/install.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | $: << "#{ENV['CRAILS_SHARED_DIR']}/scripts/lib" 4 | 5 | require 'project_model' 6 | require 'cmakelists' 7 | require 'maincpp' 8 | 9 | project = ProjectModel.new 10 | base_directory = Dir.pwd 11 | source = "#{ENV['CRAILS_SHARED_DIR']}/app_template/signin" 12 | 13 | project.base_directory source, base_directory do 14 | project.directory :config do 15 | project.file 'signin.cpp' 16 | end 17 | end 18 | 19 | cmake = CMakeLists.new 20 | cmake.add_crails_module 'signin' 21 | cmake.write 22 | -------------------------------------------------------------------------------- /modules/signin/src/model.cpp: -------------------------------------------------------------------------------- 1 | #include "crails/signin/model.hpp" 2 | #include "crails/utils/string.hpp" 3 | #include 4 | 5 | using namespace std; 6 | using namespace Crails; 7 | 8 | void AuthenticableModel::generate_authentication_token() 9 | { 10 | static const string charset( 11 | "abcdefghijklmnopqrstuvwxyz" 12 | "ABCDEFGHUJKLMNOPQRSTUVWXYZ" 13 | "1234567890" 14 | "!@$^*()" 15 | "`~-_{};:,<> " 16 | ); 17 | 18 | set_authentication_token(Crails::generate_random_string(charset, 16)); 19 | } 20 | 21 | time_t AuthenticableModel::get_token_expires_in() const 22 | { 23 | if (sign_in_at != 0) 24 | { 25 | using namespace chrono; 26 | auto now = system_clock::now(); 27 | 28 | return session_duration - (system_clock::to_time_t(now) - sign_in_at); 29 | } 30 | return session_duration; 31 | } 32 | -------------------------------------------------------------------------------- /modules/sync/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(crails-sync) 4 | 5 | include_directories(. ../odb) 6 | 7 | file(GLOB crails_sync src/*.cpp) 8 | 9 | file(GLOB headers_crails_sync crails/sync/*.hpp) 10 | file(GLOB headers_crails_odb crails/odb/*.hpp) 11 | 12 | file(GLOB crails_sync_templates app/config/sync.cpp) 13 | 14 | file(GLOB crails_sync_scripts scripts/modules/sync/*.rb) 15 | 16 | add_library(crails-sync${crails-suffix} SHARED ${crails_sync}) 17 | 18 | install(FILES ${headers_crails_sync} DESTINATION include/crails/sync) 19 | install(FILES ${headers_crails_odb} DESTINATION include/crails/odb) 20 | install(FILES ${crails_sync_templates} DESTINATION share/crails/app_template/sync) 21 | install(FILES ${crails_sync_scripts} DESTINATION share/crails/scripts/modules/sync) 22 | install(TARGETS crails-sync${crails-suffix} LIBRARY DESTINATION lib) 23 | -------------------------------------------------------------------------------- /modules/sync/app/config/sync.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | thread_local Faye::Client faye({ 5 | Crails::getenv ("FAYE_PROTOCOL", "http"), 6 | Crails::getenv ("FAYE_HOST", "localhost"), 7 | Crails::getenv_as("FAYE_PORT", 9292), 8 | [](Data message) { 9 | message["ext"]["secret"] = Crails::getenv("FAYE_SECRET"); 10 | } 11 | }); 12 | -------------------------------------------------------------------------------- /modules/sync/crails/sync/client.hpp: -------------------------------------------------------------------------------- 1 | #ifndef FAYE_CLIENT_HPP 2 | # define FAYE_CLIENT_HPP 3 | 4 | # include 5 | # include 6 | # include 7 | 8 | namespace Faye 9 | { 10 | class Client 11 | { 12 | public: 13 | struct Settings 14 | { 15 | const std::string protocol, hostname; 16 | const unsigned short port; 17 | const std::function hook; 18 | }; 19 | 20 | Client(const Settings& settings); 21 | 22 | void publish(const std::string& channel, Data message); 23 | private: 24 | std::string url_for_channel(const std::string& channel) const; 25 | 26 | Settings settings; 27 | boost::network::http::client http; 28 | }; 29 | } 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /modules/sync/crails/sync/task.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SYNC_TASK_HPP 2 | # define SYNC_TASK_HPP 3 | 4 | # include 5 | # include 6 | 7 | namespace Sync 8 | { 9 | class Task 10 | { 11 | const unsigned int notification_step_perc = 5; 12 | 13 | std::string id; 14 | unsigned int last_notification = 0; 15 | unsigned int task_progress = 0; 16 | unsigned int task_count = 1; 17 | public: 18 | DataTree metadata; 19 | 20 | Task(unsigned int task_count); 21 | Task(const std::string& id, unsigned int task_count); 22 | ~Task(); 23 | 24 | void set_task_count(unsigned int); 25 | unsigned int notification_step() const; 26 | void increment(unsigned int progress = 1); 27 | void notify(); 28 | void notify(const std::string& message); 29 | }; 30 | } 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /modules/sync/scripts/modules/sync/install.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | $: << "#{ENV['CRAILS_SHARED_DIR']}/scripts/lib" 4 | 5 | require 'project_model' 6 | require 'cmakelists' 7 | require 'maincpp' 8 | 9 | project = ProjectModel.new 10 | base_directory = Dir.pwd 11 | source = ENV['CRAILS_SHARED_DIR'] + '/app_template/sync' 12 | 13 | project.base_directory source, base_directory do 14 | project.directory :config do 15 | project.file "sync.cpp" 16 | end 17 | end 18 | 19 | cmake = CMakeLists.new 20 | cmake.add_crails_module "sync" 21 | cmake.write 22 | -------------------------------------------------------------------------------- /modules/sync/src/client.cpp: -------------------------------------------------------------------------------- 1 | #include "../crails/sync/client.hpp" 2 | #include 3 | #include 4 | 5 | using namespace Faye; 6 | using namespace std; 7 | using namespace boost; 8 | 9 | typedef network::http::client_options http_options; 10 | 11 | Client::Client(const Settings& settings) : 12 | settings(settings), 13 | http(http_options().io_service(Crails::Server::get_io_service())) 14 | { 15 | } 16 | 17 | void Client::publish(const string& channel, Data message) 18 | { 19 | DataTree object; 20 | 21 | object["channel"] = channel; 22 | object["data"] = message.to_json(); 23 | settings.hook(object.as_data()); 24 | 25 | network::http::client::request request(url_for_channel(channel)); 26 | string body = object.to_json(); 27 | 28 | request << network::header("Connection", "close"); 29 | request << network::header("Content-Length", lexical_cast(body.length())); 30 | request << network::header("Content-Type", "application/json"); 31 | request << network::body(body); 32 | http.post(request); 33 | } 34 | 35 | std::string Client::url_for_channel(const string& channel) const 36 | { 37 | return settings.protocol + "://" 38 | + settings.hostname + ':' 39 | + lexical_cast(settings.port); 40 | } 41 | -------------------------------------------------------------------------------- /modules/sync/src/sync_connection.cpp: -------------------------------------------------------------------------------- 1 | #include "../crails/odb/sync_connection.hpp" 2 | 3 | thread_local safe_ptr ODB::Sync::Connection::instance; 4 | -------------------------------------------------------------------------------- /modules/sync/src/transaction.cpp: -------------------------------------------------------------------------------- 1 | #include "../crails/sync/transaction.hpp" 2 | #include "../crails/sync/client.hpp" 3 | 4 | extern thread_local Faye::Client faye; 5 | 6 | using namespace Sync; 7 | using namespace std; 8 | 9 | namespace Sync 10 | { 11 | bool enabled = true; 12 | function Transaction::on_commit; 13 | } 14 | 15 | bool Transaction::is_enabled() 16 | { 17 | return Sync::enabled; 18 | } 19 | 20 | void Transaction::commit() 21 | { 22 | if (updates.size() + removals.size() > 0) 23 | { 24 | DataTree message; 25 | vector removal_uids; 26 | 27 | for (auto update : updates) 28 | update->render(message["updates"]); 29 | for (auto removal : removals) 30 | removal_uids.push_back(removal->uid()); 31 | message["removals"].from_vector(removal_uids); 32 | if (on_commit) 33 | on_commit(message); 34 | faye.publish("/sync", message.as_data()); 35 | rollback(); 36 | } 37 | } 38 | 39 | void Transaction::rollback() 40 | { 41 | updates.clear(); 42 | removals.clear(); 43 | } 44 | -------------------------------------------------------------------------------- /modules/xmlrpc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(crails-xmlrpc) 4 | 5 | file(GLOB crails_xmlrpc 6 | src/*.cpp) 7 | 8 | file(GLOB headers_crails_xmlrpc 9 | crails/xmlrpc/*.hpp) 10 | 11 | file(GLOB crails_xmlrpc_scripts 12 | scripts/modules/xmlrpc/*.rb) 13 | 14 | add_library(crails-xmlrpc${crails-suffix} SHARED ${crails_xmlrpc}) 15 | 16 | install(FILES ${headers_crails_xmlrpc} DESTINATION include/crails/xmlrpc) 17 | install(FILES ${crails_xmlrpc_scripts} DESTINATION share/crails/scripts/modules/xmlrpc) 18 | install(TARGETS crails-xmlrpc${crails-suffix} LIBRARY DESTINATION lib) 19 | -------------------------------------------------------------------------------- /modules/xmlrpc/crails/xmlrpc/fault.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XMLRPC_FAULT_HPP 2 | # define XMLRPC_FAULT_HPP 3 | 4 | # include "variable.hpp" 5 | # include 6 | 7 | namespace XmlRpc 8 | { 9 | class Fault : public std::exception 10 | { 11 | public: 12 | Fault(const XmlRpc::Variable& variable) : variable(variable) 13 | {} 14 | 15 | const char* what() const noexcept 16 | { 17 | return variable["faultString"].value.c_str(); 18 | } 19 | 20 | int fault_code() const 21 | { 22 | return variable["faultCode"].as_int(); 23 | } 24 | 25 | private: 26 | XmlRpc::Variable variable; 27 | }; 28 | } 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /modules/xmlrpc/crails/xmlrpc/xml_for_method_call.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XMLRPC_XML_FOR_METHOD_CALL_HPP 2 | # define XMLRPC_XML_FOR_METHOD_CALL_HPP 3 | 4 | # include "variable.hpp" 5 | # include 6 | 7 | namespace XmlRpc 8 | { 9 | template 10 | std::string xml_for_method_call(const std::string& method_name, Args... args) 11 | { 12 | std::stringstream stream; 13 | std::vector array = { args... }; 14 | 15 | stream << "\n"; 16 | stream << "\n" 17 | << " " << method_name << "\n" 18 | << " \n"; 19 | for (const auto& variable : array) 20 | { 21 | stream << " \n" 22 | << " \n"; 23 | variable.to_xml(stream); 24 | stream << '\n'; 25 | stream << " \n" 26 | << " \n"; 27 | } 28 | stream << " \n"; 29 | stream << ""; 30 | std::cout << "method call:" << std::endl << stream.str() << std::endl; 31 | return stream.str(); 32 | } 33 | } 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /modules/xmlrpc/scripts/modules/xmlrpc/install.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | $: << "#{ENV['CRAILS_SHARED_DIR']}/scripts/lib" 4 | 5 | require 'project_model' 6 | require 'cmakelists' 7 | 8 | project = ProjectModel.new 9 | base_directory = Dir.pwd 10 | 11 | cmake = CMakeLists.new 12 | cmake.add_crails_module 'xmlrpc' 13 | cmake.write 14 | -------------------------------------------------------------------------------- /modules/xmlrpc/src/client.cpp: -------------------------------------------------------------------------------- 1 | #include "../crails/xmlrpc/client.hpp" 2 | #include "../crails/xmlrpc/fault.hpp" 3 | #include 4 | 5 | using namespace std; 6 | using namespace XmlRpc; 7 | 8 | typedef boost::network::http::client_options 9 | client_options; 10 | 11 | Client::Client(const string& endpoint) : endpoint(endpoint), client(client_options().io_service(Crails::Server::get_io_service())) 12 | { 13 | } 14 | 15 | void Client::raise_xmlrpc_fault(const DataTree& data) const 16 | { 17 | XmlRpc::Variable fault_struct = XmlRpc::Variable::from_data(data["methodResponse"]["fault"]["value"]); 18 | 19 | std::cout << "Fault struct: " << fault_struct.name << std::endl; 20 | throw Fault(fault_struct); 21 | } 22 | 23 | XmlRpc::Variable Client::get_response_variable(const DataTree& data) const 24 | { 25 | const Data param = data["methodResponse"]["params"]["param"]; 26 | 27 | return Variable::from_data(param["value"]); 28 | } 29 | -------------------------------------------------------------------------------- /scripts/compile.rb: -------------------------------------------------------------------------------- 1 | $: << ENV['CRAILS_SHARED_DIR'] 2 | 3 | require 'guard' 4 | require 'guard/crails-base' 5 | 6 | Guard.setup 7 | 8 | groups = ARGV 9 | groups = ['before_compile', 'compile'] if ARGV.length == 0 10 | 11 | puts "[guard] Running guard tasks: #{groups.join ', '}" 12 | 13 | begin 14 | groups.each do |arg| 15 | guards = Guard.state.session.plugins.all.select do |g| 16 | (not g.group.nil? and g.group.name.to_sym == arg.to_sym) || 17 | g.name.to_sym == arg.to_sym 18 | end 19 | puts "[guard] Found #{guards.count} plugins" 20 | guards.each do |item| 21 | puts "[guard] Running plugin #{item.name}" 22 | item.start if item.methods.include? :start 23 | result = item.run_all 24 | item.stop if item.methods.include? :stop 25 | exit 254 if result == :failure 26 | end 27 | end 28 | rescue Exception => e 29 | puts "/!\\ crails/compile: caught exception: #{e.message}" 30 | puts e.backtrace 31 | exit 255 32 | end 33 | -------------------------------------------------------------------------------- /scripts/crails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | source = nil 4 | source = ENV['CRAILS_SHARED_DIR'] unless ENV['CRAILS_SHARED_DIR'].nil? 5 | 6 | if source.nil? 7 | (ENV['XDG_DATA_DIRS'].split ':').each do |dir| 8 | full_path = "#{dir}/crails" 9 | if File.directory? full_path 10 | source = full_path 11 | break 12 | end 13 | end 14 | end 15 | 16 | if source.nil? 17 | puts "Missing crails shared directory. Please check your installation, or manually set the environemnt variable CRAILS_SHARED_DIR." 18 | exit 1 19 | else 20 | ENV['CRAILS_SHARED_DIR'] = source 21 | end 22 | 23 | command = ARGV[0] 24 | command_args = ARGV[1..-1].join ' ' rescue '' 25 | 26 | if command.nil? 27 | puts 'Available commands:' 28 | Dir["#{ENV['CRAILS_SHARED_DIR']}/scripts/*.rb"].each do |cmd| 29 | cmd_name = cmd.scan(/([^\/]+)[.]rb$/).flatten.first 30 | puts " - #{cmd_name}" 31 | end 32 | exit 0 33 | end 34 | 35 | unless command == 'new' 36 | require 'fileutils' 37 | 38 | until File.exists? 'CMakeLists.txt' 39 | FileUtils.cd '..' 40 | if Dir.pwd == '/' 41 | puts 'You\'re not in a Crails application' 42 | exit -2 43 | end 44 | end 45 | end 46 | 47 | ## 48 | ## Run the command with the proper bundling environment 49 | ## 50 | commands_without_bundler = ['new'] 51 | 52 | require "#{source}/scripts/lib/bundle.rb" 53 | 54 | cmd = "ruby #{source}/scripts/#{command}.rb #{command_args}" 55 | if commands_without_bundler.include? command 56 | exit run_command cmd 57 | else 58 | exit run_using_bundler cmd 59 | end 60 | -------------------------------------------------------------------------------- /scripts/guard.rb: -------------------------------------------------------------------------------- 1 | arguments = $*.map {|i| "'#{i}'"} 2 | 3 | cmd = "guard #{arguments.join ' '}" 4 | exec cmd 5 | -------------------------------------------------------------------------------- /scripts/guard/crails-cmake.rb: -------------------------------------------------------------------------------- 1 | require 'guard/crails-base' 2 | require 'guard/crails-notifier' 3 | 4 | module ::Guard 5 | class CrailsCmake < CrailsPlugin 6 | def run_all 7 | compile 8 | end 9 | 10 | def run_on_modifications(paths) 11 | run_all 12 | end 13 | 14 | private 15 | def compile 16 | Crails::Notifier.notify get_project_name, "Compiling..." 17 | success = false 18 | duration = nil 19 | success = run_cmake 20 | if success 21 | Dir.chdir build_path do 22 | puts ">> Make server" 23 | starts_at = Time.now.to_f 24 | run_command 'make' 25 | ends_at = Time.now.to_f 26 | duration = (ends_at - starts_at).round 2 27 | success = $?.success? 28 | end 29 | end 30 | if success 31 | Crails::Notifier.notify 'crails-cmake', "Compiled in #{duration}s", image: :success 32 | :success 33 | else 34 | Crails::Notifier.notify get_project_name, "Compilation failed", image: :failed 35 | :failure 36 | end 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /scripts/guard/crails-notifier.rb: -------------------------------------------------------------------------------- 1 | module Crails 2 | module Notifier 3 | def self.notify title, message, opts = {} 4 | ::Guard::Notifier.notify( 5 | message, ({ title: title }).merge(opts) 6 | ) 7 | message_console = "#{title} - #{message}" 8 | puts ">> " + message_console.magenta 9 | end 10 | end 11 | end 12 | 13 | class String 14 | def black; "\033[30m#{self}\033[0m" end 15 | def red; "\033[31m#{self}\033[0m" end 16 | def green; "\033[32m#{self}\033[0m" end 17 | def brown; "\033[33m#{self}\033[0m" end 18 | def blue; "\033[34m#{self}\033[0m" end 19 | def magenta; "\033[35m#{self}\033[0m" end 20 | def cyan; "\033[36m#{self}\033[0m" end 21 | def gray; "\033[37m#{self}\033[0m" end 22 | def bg_black; "\033[40m#{self}\033[0m" end 23 | def bg_red; "\033[41m#{self}\033[0m" end 24 | def bg_green; "\033[42m#{self}\033[0m" end 25 | def bg_brown; "\033[43m#{self}\033[0m" end 26 | def bg_blue; "\033[44m#{self}\033[0m" end 27 | def bg_magenta; "\033[45m#{self}\033[0m" end 28 | def bg_cyan; "\033[46m#{self}\033[0m" end 29 | def bg_gray; "\033[47m#{self}\033[0m" end 30 | def bold; "\033[1m#{self}\033[22m" end 31 | def reverse_color; "\033[7m#{self}\033[27m" end 32 | 33 | COLOR_REGEXP_PATTERN = /\033\[[0-9]+m(.+?)\033\[[0-9]{1,2}m|([^\033]+)/m 34 | 35 | def uncolorize 36 | (self.scan(COLOR_REGEXP_PATTERN).collect {|v| v[0]}).join 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /scripts/guard/crails-tests.rb: -------------------------------------------------------------------------------- 1 | require 'guard/crails-base' 2 | require 'guard/crails-notifier' 3 | 4 | module ::Guard 5 | class CrailsTests < CrailsPlugin 6 | def run_all 7 | run_tests 8 | end 9 | private 10 | def run_command command 11 | last_line = nil 12 | success = true 13 | PTY.spawn(command) do |stdout, stdin, pid| 14 | begin 15 | stdout.each {|line| 16 | print line 17 | last_line = line 18 | } 19 | rescue Errno::EIO 20 | end 21 | Process.wait(pid) 22 | end 23 | last_line.uncolorize 24 | end 25 | 26 | def run_tests 27 | starts_at = Time.now.to_f 28 | command = find_test_binary 29 | last_line = run_command command 30 | success = $?.success? 31 | ends_at = Time.now.to_f 32 | image = success ? 'success' : 'failed' 33 | message = image + "\n" 34 | message += last_line.uncolorize + "\n" 35 | message += "In #{(ends_at - starts_at).round 2}s" 36 | Crails::Notifier.notify get_project_name, message, image: image 37 | if success then :success else :failure end 38 | end 39 | 40 | def find_test_binary 41 | [ "#{build_path}/tests", 'bin/tests' ].each do |candidate| 42 | return candidate if File.exists? candidate 43 | end 44 | throw "cannot find binary for crails-tests" 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /scripts/lib/bundle.rb: -------------------------------------------------------------------------------- 1 | def run_command cmd 2 | system cmd 3 | $?.exitstatus 4 | end 5 | 6 | def find_bundler 7 | bundler_gemspec = Gem::Specification::find_all_by_name('bundler') 8 | system_bundler = `which bundle 2> /dev/null`.strip 9 | 10 | if bundler_gemspec.any? 11 | bundler_gem = bundler_gemspec.first 12 | path = "#{bundler_gem.bin_dir}/#{bundler_gem.executables.first}" 13 | path = if File.exists? path then path else nil end 14 | end 15 | 16 | if !path.nil? 17 | path 18 | elsif system_bundler != "" 19 | system_bundler 20 | else 21 | nil 22 | end 23 | end 24 | 25 | def bundle_install 26 | bundler_bin = find_bundler 27 | 28 | if bundler_bin.nil? 29 | puts "/!\\ Bundler gem not found. Please install it with `gem install bundler`." 30 | exit 2 31 | end 32 | 33 | puts "+ #{bundler_bin} install" 34 | run_command "#{bundler_bin} install" 35 | end 36 | 37 | def run_using_bundler cmd 38 | bundler_bin = find_bundler 39 | 40 | if bundler_bin.nil? 41 | puts "/!\\ Bundler gem not found. Please install it with `gem install bundler`." 42 | exit 2 43 | end 44 | 45 | puts "[crails] Using ruby bundler #{bundler_bin}" 46 | 47 | bundle_cmd = "#{bundler_bin} install" 48 | 49 | unless ENV['CRAILS_RUBY_BUNDLE_PATH'].nil? 50 | config_cmd = "#{bundler_bin} config set path #{ENV['CRAILS_RUBY_BUNDLE_PATH']}" 51 | run_command config_cmd 52 | bundle_cmd += " --path #{ENV['CRAILS_RUBY_BUNDLE_PATH']}" 53 | end 54 | 55 | cmd = "#{bundler_bin} exec #{cmd}" 56 | 57 | puts `echo "+ bundle check" && #{bundler_bin} check` 58 | cmd = "#{bundle_cmd} && #{cmd}" unless $?.success? 59 | run_command cmd 60 | end 61 | -------------------------------------------------------------------------------- /scripts/lib/project_model.rb: -------------------------------------------------------------------------------- 1 | require 'fileutils' 2 | require 'erb' 3 | 4 | class ProjectModel 5 | include FileUtils 6 | 7 | def base_directory template_path, path, &block 8 | @template_path = template_path 9 | directory path do block.call end 10 | end 11 | 12 | def directory path, &block 13 | makedir path 14 | cd path.to_s, verbose: false do 15 | block.call 16 | end 17 | end 18 | 19 | def file name, source = nil 20 | action = "CREATE" 21 | if File.exists? name 22 | print "\033[35m[?]\033[0m File #{name} exists. Overwrite ? [y/n] " 23 | answer = STDIN.gets.chomp 24 | action = if answer =~ /^y(es){0,1}$/ 25 | "REPLACE" 26 | else 27 | "EXISTS" 28 | end 29 | end 30 | if action != "EXISTS" 31 | source = name if source.nil? 32 | cp "#{@template_path}/#{source}", name.to_s 33 | end 34 | puts "\033[32m[#{action}]\033[0m " + "File #{name}" 35 | end 36 | 37 | def generate_erb target, source, options 38 | path = "#{@template_path}/#{source}" 39 | tpl = ERB.new (File.new path).read, nil, '-' 40 | options[:binding] ||= binding 41 | File.open target, 'w' do | f | 42 | f.write (tpl.result options[:binding]) 43 | end 44 | puts "\033[32m[GENERATED]\033[0m " + "File #{target}" 45 | end 46 | 47 | private 48 | def makedir path 49 | begin 50 | mkdir path.to_s 51 | puts "\033[32m[CREATE]\033[0m " + "Directory #{path}" 52 | rescue Errno::EEXIST 53 | puts "\033[37m[EXISTS]\033[0m " + "Directory #{path}" 54 | end 55 | end 56 | end 57 | 58 | -------------------------------------------------------------------------------- /scripts/module.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | _module = ARGV[0] 4 | command = ARGV[1] 5 | options = ARGV[2..-1] 6 | 7 | if _module.nil? 8 | puts 'Available modules:' 9 | Dir["#{ENV['CRAILS_SHARED_DIR']}/scripts/modules/*"].each do |cmd| 10 | module_name = cmd.scan(/([^\/]+)$/).flatten.first 11 | puts " - #{module_name}" 12 | end 13 | else 14 | module_script_dir = ENV['CRAILS_SHARED_DIR'] + '/scripts/modules/' + _module 15 | 16 | unless File.directory? module_script_dir 17 | puts "Could not find a crails module named `#{_module}`" 18 | exit -1 19 | end 20 | 21 | if command.nil? 22 | puts "Available commands for module #{_module}:" 23 | Dir["#{ENV['CRAILS_SHARED_DIR']}/scripts/modules/#{_module}/*"].each do |cmd| 24 | cmd_name = cmd.scan(/([^\/]+)[.]rb$/).flatten.first 25 | puts " - #{cmd_name}" 26 | end 27 | else 28 | unless File.exists? "#{module_script_dir}/#{command}.rb" 29 | puts "Module `#{_module}` does not implement any command named `#{command}`" 30 | exit -2 31 | end 32 | 33 | system "ruby #{module_script_dir}/#{command}.rb #{options.join ' '}" 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /scripts/server.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | built = system 'crails compile' 3 | 4 | if built == true 5 | exec "#{Dir.pwd}/build/server", *ARGV 6 | else 7 | puts "The server won't build. Please fix the issues and try again." 8 | end 9 | -------------------------------------------------------------------------------- /scripts/set-env.rb: -------------------------------------------------------------------------------- 1 | vars = {} 2 | 3 | case ARGV[0] 4 | when 'production' 5 | vars['DEVELOPER_MODE:BOOL'] = 'OFF' 6 | when 'development' 7 | vars['DEVELOPER_MODE:BOOL'] = 'ON' 8 | when 'multithread' 9 | vars['USE_MULTITHREAD:BOOL'] = 'ON' 10 | when 'synchronous' 11 | vars['USE_MULTITHREAD:BOOL'] = 'OFF' 12 | else 13 | puts "Unknown environment #{ARGV[0]}" 14 | exit 1 15 | end 16 | 17 | build_path = if ENV['CRAILS_BUILD_PATH'].nil? then 'build' else ENV['CRAILS_BUILD_PATH'] end 18 | 19 | cmakecache = build_path + '/CMakeCache.txt' 20 | 21 | vars.each do |key,value| 22 | `sed -e s/#{key}=.*/#{key}=#{value}/ '#{cmakecache}' > .crails-set-env.tmp` 23 | `mv .crails-set-env.tmp '#{cmakecache}'` 24 | end 25 | -------------------------------------------------------------------------------- /scripts/task.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | command = ARGV[0] 4 | task_name = ARGV[1] 5 | 6 | if command.nil? 7 | puts "Usage: `crails task [command] [task_name]" 8 | exit -1 9 | end 10 | 11 | if command == 'add' 12 | $: << "#{ENV['CRAILS_SHARED_DIR']}/scripts/lib" 13 | require 'project_model' 14 | require 'cmakelists' 15 | 16 | cmakelists = CMakeLists.new 17 | cmakelists.add_crails_task task_name 18 | cmakelists.write 19 | 20 | task = ProjectModel.new 21 | source = ENV['CRAILS_SHARED_DIR'] + '/app_template/task' 22 | 23 | task.base_directory source, Dir.pwd do 24 | task.directory :tasks do 25 | task.directory task_name do 26 | task.generate_erb 'CMakeLists.txt', 'CMakeLists.txt.erb', task_name: task_name 27 | task.file 'main.cpp' 28 | end 29 | end 30 | end 31 | elsif command == 'run' 32 | command = "build/tasks/#{task_name}/task " 33 | ARGV[2..-1].each do |argv| 34 | command += "\"#{argv}\" " 35 | end 36 | system command 37 | else 38 | puts "command #{command} not found" 39 | end 40 | -------------------------------------------------------------------------------- /src/any_cast.cpp: -------------------------------------------------------------------------------- 1 | #include "crails/any_cast.hpp" 2 | #include 3 | 4 | namespace Crails 5 | { 6 | std::string any_cast(const boost::any& val) 7 | { 8 | try { 9 | return std::string(boost::any_cast(val)); 10 | } catch (...) {} 11 | return boost::any_cast(val); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/controller_basic_authentication.cpp: -------------------------------------------------------------------------------- 1 | #include "crails/controller.hpp" 2 | #include 3 | 4 | using namespace std; 5 | using namespace Crails; 6 | 7 | bool Controller::require_basic_authentication(const string& username, const string& password) 8 | { 9 | return require_basic_authentication([username, password](const string& a, const string& b) -> bool 10 | { 11 | return username == a && password == b; 12 | }); 13 | } 14 | 15 | bool Controller::require_basic_authentication(std::function acceptor) 16 | { 17 | Data authorization_header = params["headers"]["Authorization"]; 18 | 19 | if (authorization_header.exists()) 20 | return check_basic_authentication_header(authorization_header, acceptor); 21 | else 22 | { 23 | response["status"] = 401; 24 | response["headers"]["WWW-Authenticate"] = "Basic realm=\"User Visible realm\""; 25 | } 26 | return false; 27 | } 28 | 29 | bool Controller::check_basic_authentication_header(const string& authorization_header, function acceptor) 30 | { 31 | auto parts = split(authorization_header, ' '); 32 | 33 | if (parts.size() == 2 && *parts.begin() == "Basic") 34 | { 35 | string decoded_credentials = base64_decode(*parts.rbegin()); 36 | auto separator_position = decoded_credentials.find(':'); 37 | 38 | if (separator_position != string::npos) 39 | { 40 | if (acceptor(decoded_credentials.substr(0, separator_position), decoded_credentials.substr(separator_position + 1))) 41 | return true; 42 | else 43 | response["status"] = 401; 44 | } 45 | else 46 | response["status"] = 422; 47 | } 48 | else 49 | response["status"] = 422; 50 | return false; 51 | } 52 | -------------------------------------------------------------------------------- /src/cookie_data.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #ifdef CRAILS_WITH_COOKIE_ENCRYPTION 7 | # include 8 | #endif 9 | 10 | using namespace std; 11 | using namespace Crails; 12 | using namespace boost::property_tree; 13 | 14 | string CookieData::serialize(void) 15 | { 16 | try 17 | { 18 | string cookie_string; 19 | string value = this->as_data().to_json(); 20 | #ifdef CRAILS_WITH_COOKIE_ENCRYPTION 21 | Cipher cipher; 22 | 23 | if (use_encryption) 24 | value = cipher.encrypt(value, password, salt); 25 | #endif 26 | cookie_string += Http::Url::Encode("crails") + '=' + Http::Url::Encode(value); 27 | cookie_string += ";path=/"; 28 | return (cookie_string); 29 | } 30 | catch (const std::exception&) 31 | { 32 | } 33 | return (""); 34 | } 35 | 36 | void CookieData::unserialize(const string& str) 37 | { 38 | try 39 | { 40 | parse_cookie_values(str, [this](const string& key, const string& val) -> bool 41 | { 42 | if (key == "crails") 43 | { 44 | #ifdef CRAILS_WITH_COOKIE_ENCRYPTION 45 | if (use_encryption) 46 | { 47 | Cipher cipher; 48 | this->from_json(cipher.decrypt(val, password, salt)); 49 | } 50 | else 51 | #endif 52 | this->from_json(val); 53 | return false; 54 | } 55 | return true; 56 | }); 57 | } 58 | catch (const std::exception&) 59 | { 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/databases.cpp: -------------------------------------------------------------------------------- 1 | #include "crails/databases.hpp" 2 | 3 | using namespace std; 4 | using namespace Crails; 5 | 6 | thread_local Crails::Databases Crails::databases; 7 | 8 | Databases::Db::~Db() 9 | { 10 | } 11 | 12 | void Databases::cleanup_databases() 13 | { 14 | for (auto it = databases.begin() ; it != databases.end() ; ++it) 15 | delete *it; 16 | databases.clear(); 17 | } 18 | 19 | Databases::Db* Databases::get_database_from_name(const std::string& key) 20 | { 21 | for (auto it = databases.begin() ; it != databases.end() ; ++it) 22 | { 23 | if (**it == key) 24 | return (*it); 25 | } 26 | return (0); 27 | } 28 | -------------------------------------------------------------------------------- /src/environment.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | namespace Crails 6 | { 7 | #ifndef SERVER_DEBUG 8 | string environment = "production"; 9 | #else 10 | string environment = "development"; 11 | #endif 12 | } -------------------------------------------------------------------------------- /src/file_cache.cpp: -------------------------------------------------------------------------------- 1 | #include "crails/file_cache.hpp" 2 | #include "crails/read_file.hpp" 3 | 4 | using namespace std; 5 | using namespace Crails; 6 | 7 | shared_ptr FileCache::create_instance(std::string key) 8 | { 9 | shared_ptr instance = make_shared(); 10 | 11 | if (read_file(key, *instance)) 12 | return instance; 13 | return nullptr; 14 | } 15 | -------------------------------------------------------------------------------- /src/fileutils.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | struct ExtensionMatch 7 | { 8 | ExtensionMatch(const std::string& extension, const std::string& mime) : 9 | pattern(extension), 10 | regexp(extension + "$", std::regex_constants::ECMAScript | std::regex_constants::icase), 11 | mime(mime) 12 | { 13 | } 14 | 15 | std::string pattern; 16 | regex regexp; 17 | std::string mime; 18 | }; 19 | 20 | std::string get_mimetype(const std::string& filename) 21 | { 22 | static const ExtensionMatch extensions[] = { 23 | ExtensionMatch("(htm|html)(.gz|.br)?", "text/html"), 24 | ExtensionMatch("js(.gz|.br)?", "text/javascript"), 25 | ExtensionMatch("css(.gz|.br)?", "text/css"), 26 | ExtensionMatch("png", "image/png"), 27 | ExtensionMatch("(jpg|jpeg)", "image/jpg"), 28 | ExtensionMatch("bmp", "image/bmp"), 29 | ExtensionMatch("svg", "image/svg+xml"), 30 | ExtensionMatch("txt", "text/txt") 31 | }; 32 | 33 | for (unsigned short i = 0 ; i < 8 ; ++i) 34 | { 35 | if (regex_search(filename, extensions[i].regexp)) 36 | return (extensions[i].mime); 37 | } 38 | return ("application/octet-stream"); 39 | } 40 | -------------------------------------------------------------------------------- /src/getenv.cpp: -------------------------------------------------------------------------------- 1 | #include "crails/getenv.hpp" 2 | #include 3 | 4 | using namespace std; 5 | 6 | namespace Crails 7 | { 8 | string getenv(const string& varname, const string& def) 9 | { 10 | const char* value = std::getenv(varname.c_str()); 11 | 12 | if (value) 13 | return value; 14 | return def; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/params.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | using namespace Crails; 7 | 8 | Params::Params(void) 9 | { 10 | session = SessionStore::Factory(); 11 | } 12 | 13 | Params::~Params(void) 14 | { 15 | for (const File& file : files) 16 | boost::filesystem::remove(file.temporary_path); 17 | } 18 | 19 | const Params::File* Params::get_upload(const string& key) const 20 | { 21 | Files::const_iterator it = find(files.begin(), files.end(), key); 22 | 23 | if (it != files.end()) 24 | return (&(*it)); 25 | return (0); 26 | } 27 | -------------------------------------------------------------------------------- /src/password.cpp: -------------------------------------------------------------------------------- 1 | #include "crails/password.hpp" 2 | #include "crails/utils/string.hpp" 3 | 4 | using namespace std; 5 | using namespace Crails; 6 | 7 | string Password::md5(const string& str) 8 | { 9 | unsigned char result[MD5_DIGEST_LENGTH]; 10 | 11 | MD5((const unsigned char*)str.c_str(), str.size(), result); 12 | return (base64_encode(result, MD5_DIGEST_LENGTH)); 13 | } 14 | -------------------------------------------------------------------------------- /src/rand_str.cpp: -------------------------------------------------------------------------------- 1 | #include // for rand() 2 | #include // for isalnum() 3 | #include // for back_inserter 4 | #include 5 | 6 | static char rand_char() 7 | { 8 | const std::string charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,.;:!?&%$#()[]{}+-"; 9 | 10 | return (charset[std::rand() % charset.size()]); 11 | } 12 | 13 | std::string rand_str(std::string::size_type size) 14 | { 15 | std::string str; 16 | 17 | str.reserve(size); 18 | std::generate_n(std::back_inserter(str), size, rand_char); 19 | return (str); 20 | } -------------------------------------------------------------------------------- /src/read_file.cpp: -------------------------------------------------------------------------------- 1 | #include "crails/read_file.hpp" 2 | #include 3 | 4 | using namespace std; 5 | using namespace Crails; 6 | 7 | bool Crails::read_file(const string& filepath, string& out) 8 | { 9 | ifstream file(filepath.c_str(), std::ios::binary); 10 | 11 | if (file.is_open()) 12 | { 13 | long size, begin, end; 14 | char* raw; 15 | 16 | begin = file.tellg(); 17 | file.seekg(0, std::ios::end); 18 | end = file.tellg(); 19 | file.seekg(0, std::ios::beg); 20 | size = end - begin; 21 | raw = new char[size + 1]; 22 | file.read(raw, size); 23 | file.close(); 24 | out.resize(size); 25 | std::copy(raw, raw + size, out.begin()); 26 | delete[] raw; 27 | return true; 28 | } 29 | return false; 30 | } 31 | -------------------------------------------------------------------------------- /src/renderer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace Crails; 4 | using namespace std; 5 | 6 | list Crails::renderers; 7 | 8 | void Renderer::finalize() 9 | { 10 | for (auto it = renderers.begin() ; it != renderers.end() ; ++it) 11 | delete *it; 12 | renderers.clear(); 13 | } 14 | 15 | void Renderer::render(const std::string& view, Data params, Data response, SharedVars& vars) 16 | { 17 | const Renderer* renderer = pick_renderer(view, params); 18 | 19 | if (renderer == NULL) 20 | throw MissingTemplate(view, params["headers"]["Accept"].defaults_to(default_format)); 21 | renderer->render_template(view, params, response, vars); 22 | } 23 | 24 | Renderer* Renderer::pick_renderer(const std::string& view, Data params) 25 | { 26 | string format = params["headers"]["Accept"].defaults_to(default_format); 27 | 28 | for (auto it = renderers.begin() ; it != renderers.end() ; ++it) 29 | { 30 | if ((*it)->can_render(format, view)) 31 | return *it; 32 | } 33 | return NULL; 34 | } 35 | 36 | bool Renderer::can_render(const std::string& view, Data params) 37 | { 38 | return pick_renderer(view, params) != NULL; 39 | } 40 | -------------------------------------------------------------------------------- /src/request_handlers/action.cpp: -------------------------------------------------------------------------------- 1 | #include "crails/request_handlers/action.hpp" 2 | #include "crails/router.hpp" 3 | #include "crails/logger.hpp" 4 | 5 | using namespace std; 6 | using namespace Crails; 7 | 8 | void ActionRequestHandler::operator()(const HttpServer::request& request, BuildingResponse& out, Params& params, function callback) 9 | { 10 | const Router* router = Router::singleton::Get(); 11 | 12 | if (router) 13 | { 14 | string method = params["_method"].defaults_to(request.method); 15 | const Router::Action* action = router->get_action(method, params["uri"].as(), params); 16 | 17 | if (action == 0) 18 | callback(false); 19 | else 20 | { 21 | logger << Logger::Info << "# Responding to " << method << ' ' << params["uri"].as() << Logger::endl; 22 | params.session->load(params["headers"]); 23 | (*action)(params, [callback,¶ms,&out](DataTree data) 24 | { 25 | string body = data["body"].defaults_to(""); 26 | Server::HttpCode code; 27 | 28 | if (data["headers"].exists()) 29 | { 30 | data["headers"].each([&out](Data header) -> bool 31 | { 32 | out.set_headers(header.get_key(), header.as()); 33 | return true; 34 | }); 35 | } 36 | params.session->finalize(out); 37 | code = (Server::HttpCode)(data["status"].defaults_to(200)); 38 | Server::SetResponse(params, out, code, body); 39 | callback(true); 40 | }); 41 | } 42 | } 43 | else 44 | callback(false); 45 | } 46 | 47 | -------------------------------------------------------------------------------- /src/request_parser.cpp: -------------------------------------------------------------------------------- 1 | #include "crails/request_parser.hpp" 2 | #include "crails/params.hpp" 3 | 4 | using namespace std; 5 | using namespace Crails; 6 | 7 | bool RequestParser::content_type_matches(Params& params, const regex regexp) 8 | { 9 | Data headers = params["headers"]; 10 | vector supported_headers = {"Content-Type","content-type"}; 11 | 12 | for (string header_key : supported_headers) 13 | { 14 | if (params["headers"][header_key].exists()) 15 | { 16 | string type = params["headers"][header_key].as(); 17 | 18 | return regex_search(type, regexp); 19 | } 20 | } 21 | return false; 22 | } 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/request_parsers/data_parser.cpp: -------------------------------------------------------------------------------- 1 | #include "crails/server.hpp" 2 | #include "crails/params.hpp" 3 | 4 | using namespace std; 5 | using namespace Crails; 6 | 7 | void RequestDataParser::operator()(const HttpServer::request& request, BuildingResponse&, Params& params, function callback) 8 | { 9 | { 10 | const char* get_params = strrchr(request.destination.c_str(), '?'); 11 | std::string uri = request.destination; 12 | 13 | // Setting Headers parameters 14 | { 15 | auto it = request.headers.begin(); 16 | auto end = request.headers.end(); 17 | 18 | for (; it != end ; ++it) 19 | { 20 | boost::network::http::request_header_narrow header = *it; 21 | params["headers"][header.name] = header.value; 22 | } 23 | } 24 | 25 | // Getting get parameters 26 | if (get_params != 0) 27 | { 28 | std::string str_params(get_params); 29 | 30 | uri.erase(uri.size() - str_params.size()); 31 | str_params.erase(0, 1); 32 | cgi2params(params.as_data(), str_params); 33 | } 34 | 35 | // Set URI and method for the posterity (is that even a word ?) 36 | params["uri"] = uri; 37 | params["method"] = request.method; 38 | } 39 | callback(RequestParser::Continue); 40 | } 41 | -------------------------------------------------------------------------------- /src/request_parsers/form_parser.cpp: -------------------------------------------------------------------------------- 1 | #include "crails/server.hpp" 2 | #include "crails/params.hpp" 3 | #include "crails/logger.hpp" 4 | #include "crails/utils/regex.hpp" 5 | 6 | using namespace std; 7 | using namespace Crails; 8 | 9 | void RequestFormParser::operator()(const HttpServer::request& request, BuildingResponse& out, Params& params, function callback) 10 | { 11 | static const regex is_form("application/x-www-form-urlencoded", regex_constants::extended); 12 | 13 | if (params["method"].as() != "GET" && content_type_matches(params, is_form)) 14 | { 15 | wait_for_body(request, out, params, [callback]() 16 | { 17 | callback(RequestParser::Stop); 18 | }); 19 | } 20 | else 21 | callback(RequestParser::Continue); 22 | } 23 | 24 | void RequestFormParser::body_received(const HttpServer::request& request, BuildingResponse&, Params& params, const string& body) 25 | { 26 | if (body.size() > 0) 27 | cgi2params(params.as_data(), body); 28 | } 29 | -------------------------------------------------------------------------------- /src/request_parsers/json_parser.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | using namespace Crails; 7 | using namespace boost::property_tree; 8 | 9 | void RequestJsonParser::operator()(const HttpServer::request& request, BuildingResponse& out, Params& params, function callback) 10 | { 11 | static const regex is_json("application/json", regex_constants::extended); 12 | 13 | if (params["method"].as() != "GET" && content_type_matches(params, is_json)) 14 | { 15 | wait_for_body(request, out, params, [callback]() 16 | { 17 | callback(RequestParser::Stop); 18 | }); 19 | } 20 | else 21 | callback(RequestParser::Continue); 22 | } 23 | 24 | void RequestJsonParser::body_received(const HttpServer::request& request, BuildingResponse&, Params& params, const string& body) 25 | { 26 | if (body.size() > 0) 27 | params.as_data().merge(DataTree().from_json(body)); 28 | } 29 | -------------------------------------------------------------------------------- /src/request_parsers/xml_parser.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | using namespace Crails; 7 | using namespace boost::property_tree; 8 | 9 | void RequestXmlParser::operator()(const HttpServer::request& request, BuildingResponse& out, Params& params, function callback) 10 | { 11 | static const regex is_xml("(application|text)/xml", regex_constants::extended); 12 | 13 | if (params["method"].as() != "GET" && content_type_matches(params, is_xml)) 14 | { 15 | wait_for_body(request, out, params, [callback]() 16 | { 17 | callback(RequestParser::Stop); 18 | }); 19 | } 20 | else 21 | callback(RequestParser::Continue); 22 | } 23 | 24 | void RequestXmlParser::body_received(const HttpServer::request& request, BuildingResponse&, Params& params, const string& body) 25 | { 26 | if (body.size() > 0) 27 | { 28 | params["document"] = 0; 29 | params["document"].merge(DataTree().from_xml(body)); 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /src/session_cookie_store.cpp: -------------------------------------------------------------------------------- 1 | #include "crails/session_store/cookie_store.hpp" 2 | 3 | using namespace std; 4 | using namespace Crails; 5 | 6 | void CookieStore::load(Data request_headers) 7 | { 8 | string cookie_string = request_headers["Cookie"].defaults_to(""); 9 | 10 | cookies.unserialize(cookie_string); 11 | } 12 | 13 | void CookieStore::finalize(BuildingResponse& response) 14 | { 15 | if (cookies.as_data().count() > 0) 16 | response.set_headers("Set-Cookie", cookies.serialize()); 17 | } 18 | 19 | Data CookieStore::to_data(void) 20 | { 21 | return (cookies.as_data()); 22 | } 23 | -------------------------------------------------------------------------------- /src/shared_vars.cpp: -------------------------------------------------------------------------------- 1 | #include "crails/shared_vars.hpp" 2 | #include "crails/logger.hpp" 3 | 4 | using namespace Crails; 5 | using namespace std; 6 | 7 | void Crails::output_shared_vars(const SharedVars& vars) 8 | { 9 | logger << Logger::Debug; 10 | for (auto item : vars) 11 | { 12 | const string& var_name = item.first; 13 | const string& type_name = item.second.type().name(); 14 | 15 | logger << "shared_vars[\"" << var_name << "\"] -> " << type_name << "\n"; 16 | } 17 | logger << Logger::endl; 18 | } 19 | -------------------------------------------------------------------------------- /src/template.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace Crails; 4 | using namespace std; 5 | 6 | std::string Template::partial(const std::string& view, SharedVars vars_) 7 | { 8 | auto tpl = renderer->templates.find(view); 9 | 10 | if (tpl == renderer->templates.end()) 11 | throw MissingTemplate(view); 12 | else 13 | { 14 | SharedVars duplicate = vars; 15 | 16 | for (auto& var : vars_) 17 | duplicate[var.first] = var.second; 18 | return (*tpl).second(renderer, duplicate); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/tests/main.cpp: -------------------------------------------------------------------------------- 1 | #include "crails/tests/runner.hpp" 2 | #include "crails/router.hpp" 3 | #include "crails/databases.hpp" 4 | #include 5 | 6 | using namespace std; 7 | using namespace Crails; 8 | using namespace Crails::Tests; 9 | 10 | int main(int, char**) 11 | { 12 | Runner runner; 13 | int exit_status = 1; 14 | 15 | Crails::environment = "test"; 16 | Router::singleton::Initialize(); 17 | Router::singleton::Get()->initialize(); 18 | runner.setup(); 19 | if (runner.execute()) 20 | exit_status = 0; 21 | runner.shutdown(); 22 | Router::singleton::Finalize(); 23 | return exit_status; 24 | } 25 | -------------------------------------------------------------------------------- /src/tests/request.cpp: -------------------------------------------------------------------------------- 1 | #include "crails/tests/request.hpp" 2 | 3 | using namespace std; 4 | using namespace Crails; 5 | 6 | Tests::Request::Request(const string& method, const std::string& uri) 7 | { 8 | params["method"] = method; 9 | params["uri"] = uri; 10 | } 11 | 12 | void Tests::Request::run() 13 | { 14 | const Router* router = Router::singleton::Get(); 15 | 16 | if (router) 17 | { 18 | const Router::Action* action = router->get_action(params["method"].as(), params["uri"].as(), params); 19 | 20 | if (action != 0) 21 | (*action)(params, [this](DataTree data) { response = data; }); 22 | else 23 | throw RouteNotFound(params["method"].as() + '#' + params["uri"].as()); 24 | if (!response["status"].exists()) 25 | response["status"] = 200; 26 | } 27 | else 28 | throw RouterNotInitialized(); 29 | } 30 | -------------------------------------------------------------------------------- /src/tests/runner.cpp: -------------------------------------------------------------------------------- 1 | #include "crails/tests/runner.hpp" 2 | #include 3 | 4 | #define KNRM "\x1B[0m" 5 | #define KRED "\x1B[31m" 6 | #define KGRN "\x1B[32m" 7 | #define KYEL "\x1B[33m" 8 | 9 | using namespace std; 10 | using namespace Crails; 11 | using namespace Crails::Tests; 12 | 13 | bool Runner::execute() 14 | { 15 | unsigned short passed_count, failed_count, pending_count; 16 | 17 | passed_count = failed_count = pending_count = 0; 18 | cout << "Crails::Tests::Runner: Executing all tests" << endl; 19 | for_each(helpers.begin(), helpers.end(), [&passed_count, &failed_count, &pending_count](shared_ptr helper) 20 | { 21 | helper->run(); 22 | passed_count += helper->passed_count; 23 | failed_count += helper->failed_count; 24 | pending_count += helper->pending_count; 25 | }); 26 | cout << endl; 27 | cout << "Report: " << KGRN << passed_count << " passed, " << KRED << failed_count << " failed, " << KYEL << pending_count << " pendings" << KNRM << endl; 28 | return failed_count == 0; 29 | } 30 | -------------------------------------------------------------------------------- /src/utils/parse_cookie_values.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | namespace Crails 8 | { 9 | void parse_cookie_values(const string& str, std::function callback) 10 | { 11 | regex regexp("\\s*([^=]+)=([^;]*);{0,1}", regex_constants::ECMAScript); 12 | auto matches = sregex_iterator(str.begin(), str.end(), regexp); 13 | 14 | for (auto it = matches ; it != sregex_iterator() ; ++it) 15 | { 16 | smatch match = *it; 17 | string val = str.substr(match.position(2), match.length(2)); 18 | string key = str.substr(match.position(1), match.length(1)); 19 | 20 | val = Http::Url::Decode(val); 21 | key = Http::Url::Decode(key); 22 | if (!(callback(key, val))) 23 | break ; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/utils/string_split.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | namespace Crails 6 | { 7 | list split(const std::string& str, char c, bool count_repetitions) 8 | { 9 | list ret; 10 | int last_sep = -1; 11 | unsigned int i; 12 | 13 | for (i = 0 ; i < str.size() ; ++i) 14 | { 15 | if (str[i] == c) 16 | { 17 | if (i != 0 && (count_repetitions || str[i - 1] != c)) 18 | ret.push_back(str.substr(last_sep + 1, i - (last_sep + 1))); 19 | last_sep = i; 20 | } 21 | } 22 | if ((unsigned int)last_sep != i && i > 0 && str[i - 1] != c) 23 | ret.push_back(str.substr(last_sep + 1)); 24 | return (ret); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/utils/timer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace Utils; 4 | 5 | #ifdef _WIN32 6 | 7 | float Timer::GetElapsedMilliseconds(void) const 8 | { 9 | clock_t currentTime; 10 | clock_t elapsedTime; 11 | 12 | currentTime = clock(); 13 | elapsedTime = currentTime - _lastTime; 14 | return ((elapsedTime * CLOCKS_PER_SEC) / 1000.f); 15 | } 16 | 17 | 18 | void Timer::Restart() 19 | { 20 | _lastTime = clock(); 21 | } 22 | 23 | #else 24 | 25 | float Timer::GetElapsedMilliseconds(void) const 26 | { 27 | struct timeval tv; 28 | 29 | gettimeofday(&tv, 0); 30 | tv.tv_sec -= _lastTime.tv_sec; 31 | tv.tv_usec -= _lastTime.tv_usec; 32 | return (tv.tv_sec * 1000.f + tv.tv_usec / 1000.f); 33 | } 34 | 35 | 36 | void Timer::Restart() 37 | { 38 | gettimeofday(&_lastTime, 0); 39 | } 40 | 41 | #endif 42 | --------------------------------------------------------------------------------