Skip to content

Commit

Permalink
Merge pull request #74 from syucream/feature/hook_prototype
Browse files Browse the repository at this point in the history
Implement prototype of flexible hook handler class
  • Loading branch information
syucream authored Sep 18, 2016
2 parents f4b525a + a999df4 commit 1078d3d
Show file tree
Hide file tree
Showing 14 changed files with 598 additions and 172 deletions.
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

0 comments on commit 1078d3d

Please sign in to comment.