7#define GCDEBUG(...)      Ase::debug ("gc", __VA_ARGS__) 
    8#define GCDEBUG_ENABLED() Ase::debug_key_enabled ("gc") 
   12static String subprotocol_authentication;
 
   15jsonapi_set_subprotocol (
const String &subprotocol)
 
   17  subprotocol_authentication = subprotocol;
 
   21class JsonapiConnection;
 
   24static JsonapiConnectionP current_message_conection;
 
   27is_localhost (
const String &url, 
int port)
 
   29  return Re::search (
"^https?://(localhost|127\\.0\\.0\\.1)(:[0-9]+)?/", url, Re::I) >= 0;
 
   35  log (
const String &message)
 override 
   37    printerr (
"%s: %s\n", nickname(), message);
 
   42    using namespace AnsiColors;
 
   43    const auto C1 = color (BOLD), C0 = color (BOLD_OFF);
 
   44    const Info info = get_info();
 
   45    const String origin = info.header (
"Origin") + 
"/";
 
   46    const bool localhost_origin = is_localhost (origin, info.lport);
 
   47    const bool subproto_ok = (info.subs.
size() == 0 && subprotocol_authentication.
empty()) ||
 
   48                             (info.subs.
size() == 1 && subprotocol_authentication == info.subs[0]);
 
   49    if (localhost_origin && subproto_ok)
 
   53    if (!localhost_origin)      why = 
"Bad Origin";
 
   54    else if (!subproto_ok)      why = 
"Bad Subprotocol";
 
   55    const String ua = info.header (
"User-Agent");
 
   57      log (
string_format (
"%sREJECT:%s  %s:%d/ (%s) - %s", C1, C0, info.remote, info.rport, why, ua));
 
   63    using namespace AnsiColors;
 
   64    const auto C1 = color (BOLD), C0 = color (BOLD_OFF);
 
   65    const Info info = get_info();
 
   66    const String ua = info.header (
"User-Agent");
 
   68      log (
string_format (
"%sACCEPT:%s  %s:%d/ - %s", C1, C0, info.remote, info.rport, ua));
 
   73    using namespace AnsiColors;
 
   74    const auto C1 = color (BOLD), C0 = color (BOLD_OFF);
 
   77    trigger_destroy_hooks();
 
   80  message (
const String &message)
 override 
   87    main_jobs += [&message, &reply, conp, &sem, 
this] () {
 
   88      current_message_conection = conp;
 
   89      reply = handle_jsonipc (message);
 
   90      current_message_conection = 
nullptr;
 
  107    trigger_destroy_hooks();
 
  112    const bool starting_gc = imap_.mark_unused();
 
  113    GCDEBUG (
"%s: imap_=%d%s\n", __func__, imap_.size(), starting_gc ? 
" (duplicate)" : 
"");
 
  119    const size_t preerved = imap_.purge_unused (ids);
 
  120    GCDEBUG (
"%s: considered=%d retained=%d purged=%d active=%d\n", __func__,
 
  121             ids.size(), preerved, ids.size() - preerved, imap_.size());
 
  125  trigger_lookup (
const String &
id)
 
  127    for (
auto it = triggers_.begin(); it != triggers_.end(); it++)
 
  133  trigger_remove (
const String &
id)
 
  135    trigger_lookup (
id).destroy();
 
  138  trigger_create (
const String &
id)
 
  140    using namespace Jsonipc;
 
  144    const int logflags = logflags_;
 
  146    auto trigger_remote = [selfw, id, logflags] (
ValueS &&args)    
 
  150      const String msg = jsonobject_to_string (
"method", 
id , 
"params", args);
 
  153      selfp->send_text (msg);
 
  155    JsTrigger trigger = JsTrigger::create (
id, trigger_remote);
 
  156    triggers_.push_back (trigger);
 
  158    auto erase_trigger = [selfw, id, logflags] ()               
 
  162      if (selfp->is_open())
 
  165          const String msg = jsonobject_to_string (
"method", 
"Jsonapi/Trigger/killed", 
"params", args);
 
  168          selfp->send_text (msg);
 
  170      Aux::erase_first (selfp->triggers_, [
id] (
auto &t) { return id == t.id(); });
 
  172    trigger.ondestroy (erase_trigger);
 
  175  trigger_destroy_hooks()
 
  178    old.swap (triggers_); 
 
  179    for (
auto &trigger : old)
 
  181    custom_data_destroy();
 
 
  191#define ERROR500(WHAT)                                          \ 
  192  Jsonipc::bad_invocation (-32500,                              \ 
  194                           ASE_CPP_STRINGIFY (__LINE__) ": "    \ 
  195                           "Internal Server Error: "            \ 
  197#define assert_500(c) (__builtin_expect (static_cast<bool> (c), 1) ? (void) 0 : throw ERROR500 (#c) ) 
  202  using namespace Jsonipc;
 
  205    dispatcher->add_method (
"Jsonapi/renew-gc",
 
  208                              assert_500 (current_message_conection);
 
  209                              if (cbi.n_args() > 0)
 
  211                              const auto ret = current_message_conection->renew_gc ();
 
  212                              cbi.set_result (to_json (ret, cbi.allocator()).Move());
 
  214    dispatcher->add_method (
"Jsonapi/report-gc",
 
  217                              assert_500 (current_message_conection);
 
  218                              if (cbi.n_args() != 1)
 
  220                              const auto ids = from_json<std::vector<size_t>> (cbi.ntharg (0));
 
  221                              const auto ret = current_message_conection->report_gc (ids);
 
  222                              cbi.set_result (to_json (ret, cbi.allocator()).Move());
 
  224    dispatcher->add_method (
"Jsonapi/initialize",
 
  227                              assert_500 (current_message_conection);
 
  228                              Server &server = ASE_SERVER;
 
  230                              cbi.set_result (to_json (serverp, cbi.allocator()).Move());
 
  232    dispatcher->add_method (
"Jsonapi/Trigger/create",
 
  235                              assert_500 (current_message_conection);
 
  236                              const String triggerid = cbi.n_args() == 1 ? from_json<String> (cbi.ntharg (0)) : 
"";
 
  237                              if (triggerid.compare (0, 17, 
"Jsonapi/Trigger/_") != 0)
 
  239                              current_message_conection->trigger_create (triggerid);
 
  241    dispatcher->add_method (
"Jsonapi/Trigger/remove",
 
  244                              assert_500 (current_message_conection);
 
  245                              const String triggerid = cbi.n_args() == 1 ? from_json<String> (cbi.ntharg (0)) : 
"";
 
  246                              if (triggerid.compare (0, 17, 
"Jsonapi/Trigger/_") != 0)
 
  248                              current_message_conection->trigger_remove (triggerid);
 
  256JsonapiConnection::handle_jsonipc (
const std::string &message)
 
  263    CoalesceNotifies coalesce_notifies; 
 
  264    reply = make_dispatcher()->dispatch_message (message);
 
  268      const char *errorat = 
strstr (reply.c_str(), 
"\"error\":{");
 
  269      if (errorat && errorat > reply.c_str() && (errorat[-1] == 
',' || errorat[-1] == 
'{'))
 
  271          using namespace AnsiColors;
 
  276        log (
string_format (
"← %s", reply.size() > 1024 ? reply.substr (0, 1020) + 
"..." + reply.back() : reply));
 
  291  Impl& operator= (
const Impl&) = 
delete;
 
  304    while (!destroyhooks.empty())
 
  306        VoidFunc destroyhook = destroyhooks.back();
 
  307        destroyhooks.pop_back();
 
 
  314JsTrigger::ondestroy (
const VoidFunc &vf)
 
  318    p_->destroyhooks.push_back (vf);
 
  322JsTrigger::call (
ValueS &&args)
 const 
  326    p_->func (std::move (args));
 
  330JsTrigger::create (
const String &triggerid, 
const JsTrigger::Impl::Func &f)
 
  339JsTrigger::id ()
 const 
  341  return p_ ? p_->id : 
"";
 
  351JsTrigger::operator 
bool () const noexcept
 
  353  return p_ && p_->func;
 
  357ConvertJsTrigger::lookup (
const String &triggerid)
 
  359  if (current_message_conection)
 
  360    return current_message_conection->trigger_lookup (triggerid);
 
  366jsonapi_connection_data ()
 
  368  if (current_message_conection)
 
  369    return current_message_conection.get();
 
  374jsonapi_connection_sender ()
 
  377  JsonapiConnectionW conw = current_message_conection;
 
  378  return [conw] (
const String &blob) {
 
  379    JsonapiConnectionP conp = conw.lock();
 
  380    return conp ? conp->send_binary (blob) : 
false;
 
  400  for (
size_t i = 1; i <= 99; i++)
 
  401    tmap[1000 - i] = string_format (
"%d", i);
 
  403  for (
auto it = tmap.begin(), next = it; it != tmap.end() ? ++
next, 1 : 0; it = 
next) 
 
Callback mechanism for Jsonapi/Jsonipc.
 
static ssize_t search(const String ®ex, const String &input, Flags=DEFAULT)
Find regex in input and return match position >= 0 or return < 0 otherwise.
 
int wait() noexcept
Unlock ScopedSemaphore.
 
int post() noexcept
Unlock ScopedSemaphore.
 
bool send_text(const String &message)
Returns true if text message was sent.
 
Keep track of temporary instances during IpcDispatcher::dispatch_message().
 
#define assert_return(expr,...)
Return from the current function if expr is unmet and issue an assertion warning.
 
#define return_unless(cond,...)
Return silently if cond does not evaluate to true with return value ...
 
#define TEST_INTEGRITY(FUNC)
Register func as an integrity test.
 
std::string color(Colors acolor, Colors c1, Colors c2, Colors c3, Colors c4, Colors c5, Colors c6)
Return ANSI code for the specified color if stdout & stderr should be colorized, see colorize_tty().
 
size_t erase_first(C &container, const std::function< bool(typename C::value_type const &value)> &pred)
Erase first element for which pred() is true in vector or list.
 
The Anklang C++ API namespace.
 
std::string string_format(const char *format, const Args &...args) __attribute__((__format__(__printf__
Format a string similar to sprintf(3) with support for std::string and std::ostringstream convertible...
 
JobQueue main_jobs(call_main_loop)
Execute a job callback in the Ase main loop.
 
std::string String
Convenience alias for std::string.
 
T shared_from_this(T... args)
 
Context for calling C++ functions from Json.
 
Jsonipc exception that is relayed to caller when thrown during invocations.
 
#define TASSERT(cond)
Unconditional test assertion, enters breakpoint if not fullfilled.