Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement prototype of flexible hook handler class #74

Merged
merged 11 commits into from
Sep 18, 2016
22 changes: 22 additions & 0 deletions examples/eventhandler.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
class MyHandler
def on_send_request_hdr
puts 'on_send_request_hdr'
c = ATS::Connection.new
puts c.remote_ip
end

def on_read_response_hdr
puts 'on_read_response_hdr'
c = ATS::Connection.new
puts c.remote_ip
end

def on_send_response_hdr
puts 'on_send_response_hdr'
c = ATS::Connection.new
puts c.remote_ip
end
end

es = ATS::EventSystem.new
es.register MyHandler
82 changes: 3 additions & 79 deletions src/ts_mruby.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#include <fstream>
#include <iostream>
#include <map>
#include <pthread.h>
Expand All @@ -8,57 +7,18 @@
#include <atscppapi/PluginInit.h>
#include <atscppapi/RemapPlugin.h>

#include "ts_mruby.hpp"
#include "ts_mruby_init.hpp"
#include "ts_mruby_internal.hpp"
#include "ts_mruby_internal.hpp"
#include "ts_mruby_request.hpp"
#include "utils.hpp"

using namespace std;
using namespace atscppapi;

namespace {

// Global mruby scripts cache
static MrubyScriptsCache *scriptsCache = NULL;

// key specifying thread local data
pthread_key_t threadKey = 0;

// Initialize thread key when this plugin is loaded
__attribute__((constructor)) void create_thread_keys() {
if (threadKey == 0) {
if (pthread_key_create(&threadKey, NULL) != 0) {
// XXX fatal error
}
}
}

// Note: Use pthread API's directly to have thread local parameters
ThreadLocalMRubyStates *getMrubyStates() {
auto *state =
static_cast<ThreadLocalMRubyStates *>(pthread_getspecific(threadKey));

if (!state) {
state = new ThreadLocalMRubyStates();
if (pthread_setspecific(threadKey, state)) {
// XXX fatal error
}
}

return state;
}

} // anonymous namespace

class MRubyPluginBase {
protected:
MRubyPluginBase(const string &fpath) : filepath_(fpath) {}

TSMrubyResult executeMrubyScript(Transaction &transaction) {
// get or initialize thread local mruby VM
ThreadLocalMRubyStates *states = getMrubyStates();
auto* states = ts_mruby::getThreadLocalMrubyStates();
mrb_state *mrb = states->getMrb();

// get or compile mruby script
Expand All @@ -80,34 +40,6 @@ class MRubyPluginBase {
shared_ptr<TSMrubyContext> context_;
};

ThreadLocalMRubyStates::ThreadLocalMRubyStates() {
state_ = mrb_open();
ts_mrb_class_init(state_);
}

ThreadLocalMRubyStates::~ThreadLocalMRubyStates() {
mrb_close(state_);
state_ = NULL;
}

RProc *ThreadLocalMRubyStates::getRProc(const std::string &key) {
RProc *proc = procCache_[key];
if (!proc) {
const std::string &code = scriptsCache->load(key);

// compile
mrbc_context *context = mrbc_context_new(state_);
auto *st = mrb_parse_string(state_, code.c_str(), context);
proc = mrb_generate_code(state_, st);
mrb_pool_close(st->pool);

// store to cache
procCache_.insert(make_pair(key, proc));
}

return proc;
}

class MRubyPlugin : public GlobalPlugin, MRubyPluginBase {
public:
MRubyPlugin(const string &fpath) : MRubyPluginBase(fpath) {
Expand Down Expand Up @@ -143,11 +75,7 @@ void TSPluginInit(int argc, const char *argv[]) {
RegisterGlobalPlugin(TS_MRUBY_PLUGIN_NAME, TS_MRUBY_PLUGIN_AUTHOR,
TS_MRUBY_PLUGIN_EMAIL);

if (!scriptsCache) {
scriptsCache = ts_mruby::utils::mockable_ptr<MrubyScriptsCache>();
}
scriptsCache->store(argv[1]);

ts_mruby::getInitializedGlobalScriptCache(argv[1]);
new MRubyPlugin(argv[1]);
}
}
Expand All @@ -156,11 +84,7 @@ void TSPluginInit(int argc, const char *argv[]) {
TSReturnCode TSRemapNewInstance(int argc, char *argv[], void **ih,
char * /* ATS_UNUSED */, int /* ATS_UNUSED */) {
if (argc == 3) {
if (!scriptsCache) {
scriptsCache = ts_mruby::utils::mockable_ptr<MrubyScriptsCache>();
}
scriptsCache->store(argv[2]);

ts_mruby::getInitializedGlobalScriptCache(argv[2]);
new MRubyRemapPlugin(ih, argv[2]);

return TS_SUCCESS;
Expand Down
60 changes: 0 additions & 60 deletions src/ts_mruby.hpp

This file was deleted.

93 changes: 93 additions & 0 deletions src/ts_mruby_eventsystem.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
// ts_mruby_eventsystem.cpp - ts_mruby mruby module
//
*/

#include "ts_mruby_eventsystem.hpp"
#include "ts_mruby_internal.hpp"

#include <atscppapi/Transaction.h>
#include <atscppapi/utils.h>

#include <mruby.h>
#include <mruby/class.h>
#include <mruby/compile.h>
#include <mruby/data.h>
#include <mruby/proc.h>
#include <mruby/variable.h>

using namespace std;
using namespace atscppapi;

// TODO Support some aliases ... ?
static const string SEND_REQUEST_HDR_HANDLER = "on_send_request_hdr";
static const string READ_RESPONSE_HDR_HANDLER = "on_read_response_hdr";
static const string SEND_RESPONSE_HDR_HANDLER = "on_send_response_hdr";

void
EventSystemPlugin::handleSendRequestHeaders(Transaction& transaction) {
auto context = shared_ptr<TSMrubyContext>(new TSMrubyContext());
context->setTransaction(&transaction);
context->setStateTag(TransactionStateTag::SEND_REQUEST_HEADERS);

callHandler_(move(context), SEND_REQUEST_HDR_HANDLER);

transaction.resume();
}

void
EventSystemPlugin::handleReadResponseHeaders(Transaction& transaction) {
auto context = shared_ptr<TSMrubyContext>(new TSMrubyContext());
context->setTransaction(&transaction);
context->setStateTag(TransactionStateTag::READ_RESPONSE_HEADERS);

callHandler_(move(context), READ_RESPONSE_HDR_HANDLER);

transaction.resume();
}

void
EventSystemPlugin::handleSendResponseHeaders(Transaction& transaction) {
auto context = shared_ptr<TSMrubyContext>(new TSMrubyContext());
context->setTransaction(&transaction);
context->setStateTag(TransactionStateTag::SEND_RESPONSE_HEADERS);

callHandler_(move(context), SEND_RESPONSE_HDR_HANDLER);

transaction.resume();
}

mrb_value
EventSystemPlugin::callHandler_(shared_ptr<TSMrubyContext> context, const string& sym) {
auto* tlmrb = ts_mruby::getThreadLocalMrubyStates();
mrb_state* mrb = tlmrb->getMrb();
mrb->ud = reinterpret_cast<void *>(context.get());

// Run mruby script
mrb_value rv = mrb_funcall(mrb, handler_obj_->getValue(), sym.c_str(), 0, nullptr);

return rv;
}

static mrb_value ts_mrb_register_es(mrb_state *mrb,
mrb_value self) {
mrb_value argv;
mrb_get_args(mrb, "C", &argv);
struct RClass* handler_class = mrb_class_ptr(argv);

auto* context = reinterpret_cast<TSMrubyContext *>(mrb->ud);
auto* transaction = context->getTransaction();
transaction->addPlugin(new EventSystemPlugin(*transaction, mrb, handler_class));

return self;
}

void ts_mrb_eventsystem_class_init(mrb_state *mrb, struct RClass *rclass) {
struct RClass *class_es;

// EventSystem::
class_es =
mrb_define_class_under(mrb, rclass, "EventSystem", mrb->object_class);

mrb_define_method(mrb, class_es, "register", ts_mrb_register_es, MRB_ARGS_REQ(1));
}
46 changes: 46 additions & 0 deletions src/ts_mruby_eventsystem.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
// ts_mruby_eventsystem.h - ts_mruby mruby module header
//
*/

#ifndef TS_MRUBY_EVENTSYSTEM_H
#define TS_MRUBY_EVENTSYSTEM_H

#include "ts_mruby_init.hpp"
#include "ts_mruby_internal.hpp"
#include <atscppapi/Transaction.h>
#include <atscppapi/TransactionPlugin.h>
#include <mruby.h>

void ts_mrb_eventsystem_class_init(mrb_state *mrb, struct RClass *rclass);

/**
* Management plugin of EventHandling and ATS hook.
*
*/
class EventSystemPlugin : public atscppapi::TransactionPlugin {
private:
std::shared_ptr<LentMrbValue> handler_obj_;
mrb_value callHandler_(std::shared_ptr<TSMrubyContext>, const std::string&);

public:
EventSystemPlugin(atscppapi::Transaction &transaction, mrb_state* mrb, struct RClass* rclass)
: atscppapi::TransactionPlugin(transaction) {
// TODO High cost. It should switch hook resistration by any criteria.
registerHook(HOOK_SEND_REQUEST_HEADERS);
registerHook(HOOK_READ_RESPONSE_HEADERS);
registerHook(HOOK_SEND_RESPONSE_HEADERS);

// Should its handled in outer of this class?
mrb_value v = mrb_obj_new(mrb, rclass, 0, nullptr);

auto* tlmrb = ts_mruby::getThreadLocalMrubyStates();
handler_obj_ = tlmrb->getManager().lend_mrb_value(v);
}

void handleSendRequestHeaders(atscppapi::Transaction&);
void handleReadResponseHeaders(atscppapi::Transaction&);
void handleSendResponseHeaders(atscppapi::Transaction&);
};

#endif // TS_MRUBY_EVENTSYSTEM_H
2 changes: 2 additions & 0 deletions src/ts_mruby_init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "ts_mruby_init.hpp"
#include "ts_mruby_connection.hpp"
#include "ts_mruby_core.hpp"
#include "ts_mruby_eventsystem.hpp"
#include "ts_mruby_filter.hpp"
#include "ts_mruby_records.hpp"
#include "ts_mruby_request.hpp"
Expand All @@ -25,4 +26,5 @@ void ts_mrb_class_init(mrb_state *mrb) {
ts_mrb_request_class_init(mrb, rclass);
ts_mrb_upstream_class_init(mrb, rclass);
ts_mrb_records_class_init(mrb, rclass);
ts_mrb_eventsystem_class_init(mrb, rclass);
}
Loading