<commit_before>/*
 * Web Application Socket protocol, control channel library.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "was_control.hxx"
#include "was_quark.h"
#include "buffered_io.hxx"
#include "pevent.hxx"
#include "strmap.hxx"
#include "pool.hxx"
#include "fb_pool.hxx"
#include "SliceFifoBuffer.hxx"
#include "util/ConstBuffer.hxx"

#include <daemon/log.h>
#include <was/protocol.h>

#include <errno.h>
#include <string.h>

#include <stdio.h>
#include <unistd.h>

static constexpr struct timeval was_control_timeout = {
    .tv_sec = 120,
    .tv_usec = 0,
};

struct WasControl {
    struct pool *pool;

    int fd;

    bool done;

    WasControlHandler &handler;

    struct {
        struct event event;
    } input;

    struct {
        struct event event;
        unsigned bulk;
    } output;

    SliceFifoBuffer input_buffer, output_buffer;

    WasControl(struct pool &_pool, WasControlHandler &_handler)
        :pool(&_pool), handler(_handler),
         input_buffer(fb_pool_get()),
         output_buffer(fb_pool_get()) {}

    void ScheduleRead() {
        assert(fd >= 0);

        p_event_add(&input.event,
                    input_buffer.IsEmpty()
                    ? nullptr : &was_control_timeout,
                    pool, "was_control_input");
    }

    void ScheduleWrite() {
        assert(fd >= 0);

        p_event_add(&output.event, &was_control_timeout,
                    pool, "was_control_output");
    }

    /**
     * Release the socket held by this object.
     */
    void ReleaseSocket() {
        assert(fd >= 0);

        input_buffer.Free(fb_pool_get());
        output_buffer.Free(fb_pool_get());

        p_event_del(&input.event, pool);
        p_event_del(&output.event, pool);

#ifndef NDEBUG
        fd = -1;
#endif
    }

    void InvokeDone() {
        ReleaseSocket();
        handler.OnWasControlDone();
    }

    void InvokeError(GError *error) {
        assert(error != nullptr);

        ReleaseSocket();
        handler.OnWasControlError(error);
    }

    bool InvokeDrained() {
        return handler.OnWasControlDrained();
    }

    /**
     * Consume data from the input buffer.  Returns false if this object
     * has been destructed.
     */
    bool ConsumeInput();

    void TryRead();
    bool TryWrite();
};

bool
WasControl::ConsumeInput()
{
    while (true) {
        auto r = input_buffer.Read().ToVoid();
        const auto header = (const struct was_header *)r.data;
        if (r.size < sizeof(*header))
            /* not enough data yet */
            return InvokeDrained();

        if (r.size < sizeof(*header) + header->length) {
            /* not enough data yet */

            if (input_buffer.IsFull()) {
                GError *error = g_error_new(was_quark(), 0,
                                            "control header too long (%u)",
                                            header->length);
                InvokeError(error);
                return false;
            }

            return InvokeDrained();
        }

        const void *payload = header + 1;

#ifndef NDEBUG
        PoolNotify notify(*pool);
#endif

        input_buffer.Consume(sizeof(*header) + header->length);

        bool success = handler.OnWasControlPacket(was_command(header->command),
                                                  {payload, header->length});
        assert(!notify.Denotify() || !success);

        if (!success)
            return false;
    }
}

/*
 * socket i/o
 *
 */

void
WasControl::TryRead()
{
    ssize_t nbytes = recv_to_buffer(fd, input_buffer, 0xffff);
    assert(nbytes != -2);

    if (nbytes == 0) {
        GError *error =
            g_error_new_literal(was_quark(), 0,
                                "server closed the control connection");
        InvokeError(error);
        return;
    }

    if (nbytes < 0) {
        if (errno == EAGAIN) {
            ScheduleRead();
            return;
        }

        GError *error =
            g_error_new(was_quark(), 0,
                        "control receive error: %s", strerror(errno));
        InvokeError(error);
        return;
    }

    if (ConsumeInput()) {
        assert(!input_buffer.IsDefinedAndFull());
        ScheduleRead();
    }
}

bool
WasControl::TryWrite()
{
    ssize_t nbytes = send_from_buffer(fd, output_buffer);
    assert(nbytes != -2);

    if (nbytes == 0) {
        ScheduleWrite();
        return true;
    }

    if (nbytes < 0) {
        GError *error =
            g_error_new(was_quark(), 0,
                        "control send error: %s", strerror(errno));
        InvokeError(error);
        return false;
    }

    if (!output_buffer.IsEmpty())
        ScheduleWrite();
    else if (done) {
        InvokeDone();
        return false;
    } else
        p_event_del(&output.event, pool);

    return true;
}

/*
 * libevent callback
 *
 */

static void
was_control_input_event_callback(int fd gcc_unused, short event, void *ctx)
{
    WasControl *control = (WasControl *)ctx;

    assert(control->fd >= 0);

    p_event_consumed(&control->input.event, control->pool);

    if (control->done) {
        GError *error =
            g_error_new_literal(was_quark(), 0,
                                "received too much control data");
        control->InvokeError(error);
        return;
    }

    if (unlikely(event & EV_TIMEOUT)) {
        GError *error =
            g_error_new_literal(was_quark(), 0,
                                "control receive timeout");
        control->InvokeError(error);
        return;
    }

    control->TryRead();

    pool_commit();
}

static void
was_control_output_event_callback(int fd gcc_unused, short event, void *ctx)
{
    WasControl *control = (WasControl *)ctx;

    assert(control->fd >= 0);
    assert(!control->output_buffer.IsEmpty());

    p_event_consumed(&control->output.event, control->pool);

    if (unlikely(event & EV_TIMEOUT)) {
        GError *error =
            g_error_new_literal(was_quark(), 0,
                                "control send timeout");
        control->InvokeError(error);
        return;
    }

    control->TryWrite();

    pool_commit();
}

/*
 * constructor
 *
 */

WasControl *
was_control_new(struct pool *pool, int fd, WasControlHandler &handler)
{
    assert(fd >= 0);

    auto control = NewFromPool<WasControl>(*pool, *pool, handler);
    control->fd = fd;
    control->done = false;

    event_set(&control->input.event, control->fd, EV_READ|EV_TIMEOUT,
              was_control_input_event_callback, control);

    event_set(&control->output.event, control->fd, EV_WRITE|EV_TIMEOUT,
              was_control_output_event_callback, control);

    control->output.bulk = 0;

    control->ScheduleRead();

    return control;
}

bool
was_control_free(WasControl *control)
{
    control->ReleaseSocket();

    return false; // XXX
}

static void *
was_control_start(WasControl *control, enum was_command cmd,
                  size_t payload_length)
{
    assert(!control->done);

    auto w = control->output_buffer.Write().ToVoid();
    struct was_header *header = (struct was_header *)w.data;
    if (w.size < sizeof(*header) + payload_length) {
        GError *error =
            g_error_new_literal(was_quark(), 0,
                                "control output is too large");
        control->InvokeError(error);
        return nullptr;
    }

    header->command = cmd;
    header->length = payload_length;

    return header + 1;
}

static bool
was_control_finish(WasControl *control, size_t payload_length)
{
    assert(!control->done);

    control->output_buffer.Append(sizeof(struct was_header) + payload_length);
    return control->output.bulk > 0 || control->TryWrite();
}

bool
was_control_send(WasControl *control, enum was_command cmd,
                 const void *payload, size_t payload_length)
{
    assert(!control->done);

    void *dest = was_control_start(control, cmd, payload_length);
    if (dest == nullptr)
        return false;

    memcpy(dest, payload, payload_length);
    return was_control_finish(control, payload_length);
}

bool
was_control_send_string(WasControl *control, enum was_command cmd,
                        const char *payload)
{
    assert(payload != nullptr);

    return was_control_send(control, cmd, payload, strlen(payload));
}

bool
was_control_send_array(WasControl *control, enum was_command cmd,
                       ConstBuffer<const char *> values)
{
    assert(control != nullptr);

    for (auto value : values) {
        assert(value != nullptr);

        if (!was_control_send_string(control, cmd, value))
            return false;
    }

    return true;
}

bool
was_control_send_strmap(WasControl *control, enum was_command cmd,
                        const struct strmap *map)
{
    assert(control != nullptr);
    assert(map != nullptr);

    for (const auto &i : *map) {
        size_t key_length = strlen(i.key);
        size_t value_length = strlen(i.value);
        size_t payload_length = key_length + 1 + value_length;

        uint8_t *dest = (uint8_t *)
            was_control_start(control, cmd, payload_length);
        if (dest == nullptr)
            return false;

        memcpy(dest, i.key, key_length);
        dest[key_length] = '=';
        memcpy(dest + key_length + 1, i.value, value_length);
        if (!was_control_finish(control, payload_length))
            return false;
    }

    return true;
}

void
was_control_bulk_on(WasControl *control)
{
    ++control->output.bulk;
}

bool
was_control_bulk_off(WasControl *control)
{
    assert(control->output.bulk > 0);

    --control->output.bulk;
    return control->output.bulk > 0 || control->TryWrite();
}

void
was_control_done(WasControl *control)
{
    assert(!control->done);

    control->done = true;

    if (!control->input_buffer.IsEmpty()) {
        GError *error =
            g_error_new_literal(was_quark(), 0,
                                "received too much control data");
        control->InvokeError(error);
        return;
    }

    if (control->output_buffer.IsEmpty())
        control->InvokeDone();
}

bool
was_control_is_empty(WasControl *control)
{
    return control->input_buffer.IsEmpty() && control->output_buffer.IsEmpty();
}
<commit_msg>was/control: use MakeEventCallback()<commit_after>/*
 * Web Application Socket protocol, control channel library.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "was_control.hxx"
#include "was_quark.h"
#include "buffered_io.hxx"
#include "event/Callback.hxx"
#include "pevent.hxx"
#include "strmap.hxx"
#include "pool.hxx"
#include "fb_pool.hxx"
#include "SliceFifoBuffer.hxx"
#include "util/ConstBuffer.hxx"

#include <daemon/log.h>
#include <was/protocol.h>

#include <errno.h>
#include <string.h>

#include <stdio.h>
#include <unistd.h>

static constexpr struct timeval was_control_timeout = {
    .tv_sec = 120,
    .tv_usec = 0,
};

struct WasControl {
    struct pool *pool;

    int fd;

    bool done;

    WasControlHandler &handler;

    struct {
        struct event event;
    } input;

    struct {
        struct event event;
        unsigned bulk;
    } output;

    SliceFifoBuffer input_buffer, output_buffer;

    WasControl(struct pool &_pool, WasControlHandler &_handler)
        :pool(&_pool), handler(_handler),
         input_buffer(fb_pool_get()),
         output_buffer(fb_pool_get()) {}

    void ScheduleRead() {
        assert(fd >= 0);

        p_event_add(&input.event,
                    input_buffer.IsEmpty()
                    ? nullptr : &was_control_timeout,
                    pool, "was_control_input");
    }

    void ScheduleWrite() {
        assert(fd >= 0);

        p_event_add(&output.event, &was_control_timeout,
                    pool, "was_control_output");
    }

    /**
     * Release the socket held by this object.
     */
    void ReleaseSocket() {
        assert(fd >= 0);

        input_buffer.Free(fb_pool_get());
        output_buffer.Free(fb_pool_get());

        p_event_del(&input.event, pool);
        p_event_del(&output.event, pool);

#ifndef NDEBUG
        fd = -1;
#endif
    }

    void InvokeDone() {
        ReleaseSocket();
        handler.OnWasControlDone();
    }

    void InvokeError(GError *error) {
        assert(error != nullptr);

        ReleaseSocket();
        handler.OnWasControlError(error);
    }

    bool InvokeDrained() {
        return handler.OnWasControlDrained();
    }

    /**
     * Consume data from the input buffer.  Returns false if this object
     * has been destructed.
     */
    bool ConsumeInput();

    void TryRead();
    bool TryWrite();

    void ReadEventCallback(evutil_socket_t _fd, short events);
    void WriteEventCallback(evutil_socket_t _fd, short events);
};

bool
WasControl::ConsumeInput()
{
    while (true) {
        auto r = input_buffer.Read().ToVoid();
        const auto header = (const struct was_header *)r.data;
        if (r.size < sizeof(*header))
            /* not enough data yet */
            return InvokeDrained();

        if (r.size < sizeof(*header) + header->length) {
            /* not enough data yet */

            if (input_buffer.IsFull()) {
                GError *error = g_error_new(was_quark(), 0,
                                            "control header too long (%u)",
                                            header->length);
                InvokeError(error);
                return false;
            }

            return InvokeDrained();
        }

        const void *payload = header + 1;

#ifndef NDEBUG
        PoolNotify notify(*pool);
#endif

        input_buffer.Consume(sizeof(*header) + header->length);

        bool success = handler.OnWasControlPacket(was_command(header->command),
                                                  {payload, header->length});
        assert(!notify.Denotify() || !success);

        if (!success)
            return false;
    }
}

/*
 * socket i/o
 *
 */

void
WasControl::TryRead()
{
    ssize_t nbytes = recv_to_buffer(fd, input_buffer, 0xffff);
    assert(nbytes != -2);

    if (nbytes == 0) {
        GError *error =
            g_error_new_literal(was_quark(), 0,
                                "server closed the control connection");
        InvokeError(error);
        return;
    }

    if (nbytes < 0) {
        if (errno == EAGAIN) {
            ScheduleRead();
            return;
        }

        GError *error =
            g_error_new(was_quark(), 0,
                        "control receive error: %s", strerror(errno));
        InvokeError(error);
        return;
    }

    if (ConsumeInput()) {
        assert(!input_buffer.IsDefinedAndFull());
        ScheduleRead();
    }
}

bool
WasControl::TryWrite()
{
    ssize_t nbytes = send_from_buffer(fd, output_buffer);
    assert(nbytes != -2);

    if (nbytes == 0) {
        ScheduleWrite();
        return true;
    }

    if (nbytes < 0) {
        GError *error =
            g_error_new(was_quark(), 0,
                        "control send error: %s", strerror(errno));
        InvokeError(error);
        return false;
    }

    if (!output_buffer.IsEmpty())
        ScheduleWrite();
    else if (done) {
        InvokeDone();
        return false;
    } else
        p_event_del(&output.event, pool);

    return true;
}

/*
 * libevent callback
 *
 */

inline void
WasControl::ReadEventCallback(gcc_unused evutil_socket_t _fd, short events)
{
    assert(fd >= 0);

    p_event_consumed(&input.event, pool);

    if (done) {
        GError *error =
            g_error_new_literal(was_quark(), 0,
                                "received too much control data");
        InvokeError(error);
        return;
    }

    if (unlikely(events & EV_TIMEOUT)) {
        GError *error =
            g_error_new_literal(was_quark(), 0,
                                "control receive timeout");
        InvokeError(error);
        return;
    }

    TryRead();

    pool_commit();
}

inline void
WasControl::WriteEventCallback(gcc_unused evutil_socket_t _fd, short events)
{
    assert(fd >= 0);
    assert(!output_buffer.IsEmpty());

    p_event_consumed(&output.event, pool);

    if (unlikely(events & EV_TIMEOUT)) {
        GError *error =
            g_error_new_literal(was_quark(), 0,
                                "control send timeout");
        InvokeError(error);
        return;
    }

    TryWrite();

    pool_commit();
}

/*
 * constructor
 *
 */

WasControl *
was_control_new(struct pool *pool, int fd, WasControlHandler &handler)
{
    assert(fd >= 0);

    auto control = NewFromPool<WasControl>(*pool, *pool, handler);
    control->fd = fd;
    control->done = false;

    event_set(&control->input.event, control->fd, EV_READ|EV_TIMEOUT,
              MakeEventCallback(WasControl, ReadEventCallback), control);

    event_set(&control->output.event, control->fd, EV_WRITE|EV_TIMEOUT,
              MakeEventCallback(WasControl, WriteEventCallback), control);

    control->output.bulk = 0;

    control->ScheduleRead();

    return control;
}

bool
was_control_free(WasControl *control)
{
    control->ReleaseSocket();

    return false; // XXX
}

static void *
was_control_start(WasControl *control, enum was_command cmd,
                  size_t payload_length)
{
    assert(!control->done);

    auto w = control->output_buffer.Write().ToVoid();
    struct was_header *header = (struct was_header *)w.data;
    if (w.size < sizeof(*header) + payload_length) {
        GError *error =
            g_error_new_literal(was_quark(), 0,
                                "control output is too large");
        control->InvokeError(error);
        return nullptr;
    }

    header->command = cmd;
    header->length = payload_length;

    return header + 1;
}

static bool
was_control_finish(WasControl *control, size_t payload_length)
{
    assert(!control->done);

    control->output_buffer.Append(sizeof(struct was_header) + payload_length);
    return control->output.bulk > 0 || control->TryWrite();
}

bool
was_control_send(WasControl *control, enum was_command cmd,
                 const void *payload, size_t payload_length)
{
    assert(!control->done);

    void *dest = was_control_start(control, cmd, payload_length);
    if (dest == nullptr)
        return false;

    memcpy(dest, payload, payload_length);
    return was_control_finish(control, payload_length);
}

bool
was_control_send_string(WasControl *control, enum was_command cmd,
                        const char *payload)
{
    assert(payload != nullptr);

    return was_control_send(control, cmd, payload, strlen(payload));
}

bool
was_control_send_array(WasControl *control, enum was_command cmd,
                       ConstBuffer<const char *> values)
{
    assert(control != nullptr);

    for (auto value : values) {
        assert(value != nullptr);

        if (!was_control_send_string(control, cmd, value))
            return false;
    }

    return true;
}

bool
was_control_send_strmap(WasControl *control, enum was_command cmd,
                        const struct strmap *map)
{
    assert(control != nullptr);
    assert(map != nullptr);

    for (const auto &i : *map) {
        size_t key_length = strlen(i.key);
        size_t value_length = strlen(i.value);
        size_t payload_length = key_length + 1 + value_length;

        uint8_t *dest = (uint8_t *)
            was_control_start(control, cmd, payload_length);
        if (dest == nullptr)
            return false;

        memcpy(dest, i.key, key_length);
        dest[key_length] = '=';
        memcpy(dest + key_length + 1, i.value, value_length);
        if (!was_control_finish(control, payload_length))
            return false;
    }

    return true;
}

void
was_control_bulk_on(WasControl *control)
{
    ++control->output.bulk;
}

bool
was_control_bulk_off(WasControl *control)
{
    assert(control->output.bulk > 0);

    --control->output.bulk;
    return control->output.bulk > 0 || control->TryWrite();
}

void
was_control_done(WasControl *control)
{
    assert(!control->done);

    control->done = true;

    if (!control->input_buffer.IsEmpty()) {
        GError *error =
            g_error_new_literal(was_quark(), 0,
                                "received too much control data");
        control->InvokeError(error);
        return;
    }

    if (control->output_buffer.IsEmpty())
        control->InvokeDone();
}

bool
was_control_is_empty(WasControl *control)
{
    return control->input_buffer.IsEmpty() && control->output_buffer.IsEmpty();
}
<|endoftext|>


<commit_before>/*
    SWARM

    Copyright (C) 2012-2022 Torbjorn Rognes and Frederic Mahe

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

    Contact: Torbjorn Rognes <torognes@ifi.uio.no>,
    Department of Informatics, University of Oslo,
    PO Box 1080 Blindern, NO-0316 Oslo, Norway
*/

#include "swarm.h"
#include "db.h"
#include "search8.h"
#include "search16.h"
#include "threads.h"

static pthread_mutex_t scan_mutex;

static ThreadRunner * search_threads = nullptr;

struct search_data
{
  BYTE ** qtable;
  WORD ** qtable_w;

  BYTE * dprofile;
  WORD * dprofile_w;

  BYTE * hearray;

  uint64_t * dir_array;

  uint64_t target_count;
  uint64_t target_index;
};

static struct search_data * sd;
static uint64_t master_next;
static uint64_t master_length;
static uint64_t remainingchunks;
static uint64_t * master_targets;
static uint64_t * master_scores;
static uint64_t * master_diffs;
static uint64_t * master_alignlengths;
static int master_bits;
static uint64_t dirbufferbytes;

queryinfo_t query;
uint64_t longestdbsequence;

void search_alloc(struct search_data * sdp)
{
  constexpr unsigned int one_kilobyte {1024};
  constexpr unsigned int nt_per_uint64 {32};
  constexpr unsigned int bytes_per_uint64 {8};

  dirbufferbytes =
    bytes_per_uint64 * longestdbsequence * ((longestdbsequence + 3) / 4) * 4;
  sdp->qtable = new BYTE*[longestdbsequence];
  sdp->qtable_w = new WORD*[longestdbsequence];
  sdp->dprofile = new BYTE[2 * one_kilobyte];  // 4 * 16 * 32
  sdp->dprofile_w = new WORD[2 * one_kilobyte];  // 4 * 2 * 8 * 32
  sdp->hearray = new BYTE[longestdbsequence * nt_per_uint64] { };
  sdp->dir_array = new uint64_t[dirbufferbytes] { };
}

void search_free(struct search_data * sdp)
{
  delete [] sdp->qtable;
  sdp->qtable = nullptr;
  delete [] sdp->qtable_w;
  sdp->qtable_w = nullptr;
  delete [] sdp->dprofile;
  sdp->dprofile = nullptr;
  delete [] sdp->dprofile_w;
  sdp->dprofile_w = nullptr;
  delete [] sdp->hearray;
  sdp->hearray = nullptr;
  delete [] sdp->dir_array;
  sdp->dir_array = nullptr;
}

void search_init(struct search_data * sdp)
{
  constexpr int byte_multiplier {64};
  constexpr int word_multiplier {32};

  for(auto i = 0U; i < query.len; i++)
  {
    const int nt_value {nt_extract(query.seq, i) + 1};   // 1,  2,   3, or   4
    const int byte_offset {byte_multiplier * nt_value};  // 1, 64, 128, or 192
    const int word_offset {word_multiplier * nt_value};  // 1, 32,  64, or 128

    sdp->qtable[i]   = sdp->dprofile   + byte_offset;
    sdp->qtable_w[i] = sdp->dprofile_w + word_offset;
  }
}

void search_chunk(struct search_data * sdp, const int64_t bits)
{
  constexpr unsigned int bit_mode_16 {16};

  assert(sdp->target_count != 0);
  assert((bits == bit_mode_16) || (bits == bit_mode_16 / 2));

 if (bits == bit_mode_16)
   {
    search16(sdp->qtable_w,
             static_cast<WORD>(penalty_gapopen),
             static_cast<WORD>(penalty_gapextend),
             static_cast<WORD*>(score_matrix_16),
             sdp->dprofile_w,
             reinterpret_cast<WORD*>(sdp->hearray),
             sdp->target_count,
             master_targets + sdp->target_index,
             master_scores + sdp->target_index,
             master_diffs + sdp->target_index,
             master_alignlengths + sdp->target_index,
             static_cast<uint64_t>(query.len),
             dirbufferbytes / sizeof(uint64_t),
             sdp->dir_array,
             longestdbsequence);
   }
 else {
    search8(sdp->qtable,
            static_cast<BYTE>(penalty_gapopen),
            static_cast<BYTE>(penalty_gapextend),
            static_cast<BYTE*>(score_matrix_8),
            sdp->dprofile,
            sdp->hearray,
            sdp->target_count,
            master_targets + sdp->target_index,
            master_scores + sdp->target_index,
            master_diffs + sdp->target_index,
            master_alignlengths + sdp->target_index,
            static_cast<uint64_t>(query.len),
            dirbufferbytes / sizeof(uint64_t),
            sdp->dir_array,
            longestdbsequence);
 }
}

auto search_getwork(uint64_t * countref, uint64_t * firstref) -> bool
{
  // * countref = how many sequences to search
  // * firstref = index into master_targets/scores/diffs where thread should start

  bool status {false};

  pthread_mutex_lock(&scan_mutex);

  if (master_next < master_length)
    {
      const uint64_t chunksize =
        ((master_length - master_next + remainingchunks - 1) / remainingchunks);

      * countref = chunksize;
      * firstref = master_next;

      master_next += chunksize;
      remainingchunks--;
      status = true;
    }

  pthread_mutex_unlock(&scan_mutex);

  return status;
}

void search_worker_core(int64_t t)
{
  search_init(sd + t);
  while(search_getwork(& sd[t].target_count, & sd[t].target_index)) {
    search_chunk(sd + t, master_bits);
  }
}

auto adjust_thread_number(const int n_bits,
                          const uint64_t remaining_sequences,
                          uint64_t n_threads) -> uint64_t {
  constexpr unsigned int channels_8 {8};
  constexpr unsigned int channels_16 {16};
  constexpr unsigned int bit_mode_16 {16};
  auto channels {channels_16};

  assert(remaining_sequences != 0);
  assert(n_threads != 0);
  assert((n_bits == bit_mode_16) || (n_bits == bit_mode_16 / 2));

  if (n_bits == bit_mode_16) {
    channels = channels_8;
  }

  while (remaining_sequences <= (n_threads - 1) * channels) {
    --n_threads;
  }

  return n_threads;
}

// arguments: bits, master_length, thr
// static_assert(adjust_thread_number( 8, 32, 10) == 2);
// static_assert(adjust_thread_number( 8, 32,  3) == 2);
// static_assert(adjust_thread_number( 8, 31,  2) == 2);
// static_assert(adjust_thread_number( 8, 17,  2) == 2);
// static_assert(adjust_thread_number( 8, 16,  2) == 1);
// static_assert(adjust_thread_number( 8,  1,  2) == 1);
// static_assert(adjust_thread_number( 8, 32,  1) == 1);
// static_assert(adjust_thread_number(16, 17, 10) == 3);
// static_assert(adjust_thread_number(16, 17,  3) == 3);
// static_assert(adjust_thread_number(16, 16,  3) == 2);
// static_assert(adjust_thread_number(16, 15,  2) == 2);
// static_assert(adjust_thread_number(16,  1,  3) == 1);
// static_assert(adjust_thread_number(16, 17,  1) == 1);

void search_do(uint64_t query_no,
               uint64_t listlength,
               uint64_t * targets,
               uint64_t * scores,
               uint64_t * diffs,
               uint64_t * alignlengths,
               int bits)
{
  unsigned int query_len = 0;
  query.qno = query_no;
  db_getsequenceandlength(query_no, &query.seq, &query_len);
  query.len = query_len;

  master_next = 0;
  master_length = listlength;
  master_targets = targets;
  master_scores = scores;
  master_diffs = diffs;
  master_alignlengths = alignlengths;
  master_bits = bits;

  auto thr = static_cast<uint64_t>(opt_threads);

  thr = adjust_thread_number(bits, master_length, thr);

  remainingchunks = thr;

  if (thr == 1) {
    search_worker_core(0);
  }
  else {
    search_threads->run();
  }
}

void search_begin()
{
  longestdbsequence = db_getlongestsequence();

  sd = new struct search_data[static_cast<uint64_t>(opt_threads)];

  for(auto t = 0LL; t < opt_threads; t++) {
    search_alloc(sd+t);
  }

  pthread_mutex_init(& scan_mutex, nullptr);

  /* start threads */

  search_threads
    = new ThreadRunner(static_cast<int>(opt_threads), search_worker_core);
}

void search_end()
{
  /* finish and clean up worker threads */

  delete search_threads;
  search_threads = nullptr;

  pthread_mutex_destroy(& scan_mutex);

  for(auto t = 0LL; t < opt_threads; t++) {
    search_free(sd+t);
  }
  delete [] sd;
  sd = nullptr;
}
<commit_msg>add a constraint on the max number of threads<commit_after>/*
    SWARM

    Copyright (C) 2012-2022 Torbjorn Rognes and Frederic Mahe

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

    Contact: Torbjorn Rognes <torognes@ifi.uio.no>,
    Department of Informatics, University of Oslo,
    PO Box 1080 Blindern, NO-0316 Oslo, Norway
*/

#include "swarm.h"
#include "db.h"
#include "search8.h"
#include "search16.h"
#include "threads.h"

static pthread_mutex_t scan_mutex;

static ThreadRunner * search_threads = nullptr;

struct search_data
{
  BYTE ** qtable;
  WORD ** qtable_w;

  BYTE * dprofile;
  WORD * dprofile_w;

  BYTE * hearray;

  uint64_t * dir_array;

  uint64_t target_count;
  uint64_t target_index;
};

static struct search_data * sd;
static uint64_t master_next;
static uint64_t master_length;
static uint64_t remainingchunks;
static uint64_t * master_targets;
static uint64_t * master_scores;
static uint64_t * master_diffs;
static uint64_t * master_alignlengths;
static int master_bits;
static uint64_t dirbufferbytes;

queryinfo_t query;
uint64_t longestdbsequence;

void search_alloc(struct search_data * sdp)
{
  constexpr unsigned int one_kilobyte {1024};
  constexpr unsigned int nt_per_uint64 {32};
  constexpr unsigned int bytes_per_uint64 {8};

  dirbufferbytes =
    bytes_per_uint64 * longestdbsequence * ((longestdbsequence + 3) / 4) * 4;
  sdp->qtable = new BYTE*[longestdbsequence];
  sdp->qtable_w = new WORD*[longestdbsequence];
  sdp->dprofile = new BYTE[2 * one_kilobyte];  // 4 * 16 * 32
  sdp->dprofile_w = new WORD[2 * one_kilobyte];  // 4 * 2 * 8 * 32
  sdp->hearray = new BYTE[longestdbsequence * nt_per_uint64] { };
  sdp->dir_array = new uint64_t[dirbufferbytes] { };
}

void search_free(struct search_data * sdp)
{
  delete [] sdp->qtable;
  sdp->qtable = nullptr;
  delete [] sdp->qtable_w;
  sdp->qtable_w = nullptr;
  delete [] sdp->dprofile;
  sdp->dprofile = nullptr;
  delete [] sdp->dprofile_w;
  sdp->dprofile_w = nullptr;
  delete [] sdp->hearray;
  sdp->hearray = nullptr;
  delete [] sdp->dir_array;
  sdp->dir_array = nullptr;
}

void search_init(struct search_data * sdp)
{
  constexpr int byte_multiplier {64};
  constexpr int word_multiplier {32};

  for(auto i = 0U; i < query.len; i++)
  {
    const int nt_value {nt_extract(query.seq, i) + 1};   // 1,  2,   3, or   4
    const int byte_offset {byte_multiplier * nt_value};  // 1, 64, 128, or 192
    const int word_offset {word_multiplier * nt_value};  // 1, 32,  64, or 128

    sdp->qtable[i]   = sdp->dprofile   + byte_offset;
    sdp->qtable_w[i] = sdp->dprofile_w + word_offset;
  }
}

void search_chunk(struct search_data * sdp, const int64_t bits)
{
  constexpr unsigned int bit_mode_16 {16};

  assert(sdp->target_count != 0);
  assert((bits == bit_mode_16) || (bits == bit_mode_16 / 2));

 if (bits == bit_mode_16)
   {
    search16(sdp->qtable_w,
             static_cast<WORD>(penalty_gapopen),
             static_cast<WORD>(penalty_gapextend),
             static_cast<WORD*>(score_matrix_16),
             sdp->dprofile_w,
             reinterpret_cast<WORD*>(sdp->hearray),
             sdp->target_count,
             master_targets + sdp->target_index,
             master_scores + sdp->target_index,
             master_diffs + sdp->target_index,
             master_alignlengths + sdp->target_index,
             static_cast<uint64_t>(query.len),
             dirbufferbytes / sizeof(uint64_t),
             sdp->dir_array,
             longestdbsequence);
   }
 else {
    search8(sdp->qtable,
            static_cast<BYTE>(penalty_gapopen),
            static_cast<BYTE>(penalty_gapextend),
            static_cast<BYTE*>(score_matrix_8),
            sdp->dprofile,
            sdp->hearray,
            sdp->target_count,
            master_targets + sdp->target_index,
            master_scores + sdp->target_index,
            master_diffs + sdp->target_index,
            master_alignlengths + sdp->target_index,
            static_cast<uint64_t>(query.len),
            dirbufferbytes / sizeof(uint64_t),
            sdp->dir_array,
            longestdbsequence);
 }
}

auto search_getwork(uint64_t * countref, uint64_t * firstref) -> bool
{
  // * countref = how many sequences to search
  // * firstref = index into master_targets/scores/diffs where thread should start

  bool status {false};

  pthread_mutex_lock(&scan_mutex);

  if (master_next < master_length)
    {
      const uint64_t chunksize =
        ((master_length - master_next + remainingchunks - 1) / remainingchunks);

      * countref = chunksize;
      * firstref = master_next;

      master_next += chunksize;
      remainingchunks--;
      status = true;
    }

  pthread_mutex_unlock(&scan_mutex);

  return status;
}

void search_worker_core(int64_t t)
{
  search_init(sd + t);
  while(search_getwork(& sd[t].target_count, & sd[t].target_index)) {
    search_chunk(sd + t, master_bits);
  }
}

auto adjust_thread_number(const int n_bits,
                          const uint64_t remaining_sequences,
                          uint64_t n_threads) -> uint64_t {
  constexpr unsigned int channels_8 {8};
  constexpr unsigned int channels_16 {16};
  constexpr unsigned int bit_mode_16 {16};
  auto channels {channels_16};

  assert(remaining_sequences != 0);
  assert(n_threads != 0);
  assert((n_threads - 1) <= (ULLONG_MAX / channels_8));
  assert((n_bits == bit_mode_16) || (n_bits == bit_mode_16 / 2));

  if (n_bits == bit_mode_16) {
    channels = channels_8;
  }

  while (remaining_sequences <= (n_threads - 1) * channels) {
    --n_threads;
  }

  return n_threads;
}

// arguments: bits, master_length, thr
// static_assert(adjust_thread_number( 8, 32, 10) == 2);
// static_assert(adjust_thread_number( 8, 32,  3) == 2);
// static_assert(adjust_thread_number( 8, 31,  2) == 2);
// static_assert(adjust_thread_number( 8, 17,  2) == 2);
// static_assert(adjust_thread_number( 8, 16,  2) == 1);
// static_assert(adjust_thread_number( 8,  1,  2) == 1);
// static_assert(adjust_thread_number( 8, 32,  1) == 1);
// static_assert(adjust_thread_number(16, 17, 10) == 3);
// static_assert(adjust_thread_number(16, 17,  3) == 3);
// static_assert(adjust_thread_number(16, 16,  3) == 2);
// static_assert(adjust_thread_number(16, 15,  2) == 2);
// static_assert(adjust_thread_number(16,  1,  3) == 1);
// static_assert(adjust_thread_number(16, 17,  1) == 1);

void search_do(uint64_t query_no,
               uint64_t listlength,
               uint64_t * targets,
               uint64_t * scores,
               uint64_t * diffs,
               uint64_t * alignlengths,
               int bits)
{
  unsigned int query_len = 0;
  query.qno = query_no;
  db_getsequenceandlength(query_no, &query.seq, &query_len);
  query.len = query_len;

  master_next = 0;
  master_length = listlength;
  master_targets = targets;
  master_scores = scores;
  master_diffs = diffs;
  master_alignlengths = alignlengths;
  master_bits = bits;

  auto thr = static_cast<uint64_t>(opt_threads);

  thr = adjust_thread_number(bits, master_length, thr);

  remainingchunks = thr;

  if (thr == 1) {
    search_worker_core(0);
  }
  else {
    search_threads->run();
  }
}

void search_begin()
{
  longestdbsequence = db_getlongestsequence();

  sd = new struct search_data[static_cast<uint64_t>(opt_threads)];

  for(auto t = 0LL; t < opt_threads; t++) {
    search_alloc(sd+t);
  }

  pthread_mutex_init(& scan_mutex, nullptr);

  /* start threads */

  search_threads
    = new ThreadRunner(static_cast<int>(opt_threads), search_worker_core);
}

void search_end()
{
  /* finish and clean up worker threads */

  delete search_threads;
  search_threads = nullptr;

  pthread_mutex_destroy(& scan_mutex);

  for(auto t = 0LL; t < opt_threads; t++) {
    search_free(sd+t);
  }
  delete [] sd;
  sd = nullptr;
}
<|endoftext|>


<commit_before>/*
Author: vpetrigo
Task:
         .

  .      .

   .    ,
  ,   .

Sample Input:
Everyone of us has all we need

Sample Output:
Everyone

*/

#include <iostream>
#include <string>

using namespace std;

string word_size(const string& s, int& pos) {
    const char space = ' ';
    int end_of_word = s.find(space, pos);

    if (end_of_word == string::npos) {
        return string{};
    }

    string lw{s.begin() + pos, s.begin() + end_of_word};

    pos = end_of_word + 1;

    return lw;
}

int main() {
    string inp;
    int max_len = 0;
    int pos = 0;
    string longest_word;
    string word;

    getline(cin, inp);

    longest_word = word_size(inp, pos);
    word = longest_word;
    while(!word.empty()) {
        word = word_size(inp, pos);

        if (word.size() > longest_word.size()) {
            longest_word = word;
        }
    }

    cout << longest_word;

    return 0;
}<commit_msg>Solution for week 8, task 6<commit_after>/*
Author: vpetrigo
Task:
         .

  .      .

   .    ,
  ,   .

Sample Input:
Everyone of us has all we need

Sample Output:
Everyone

*/

#include <iostream>
#include <string>

using namespace std;

int main() {
    string word;
    string longest_word;

    while (cin >> word) {
        if (longest_word.empty() || word.size() > longest_word.size()) {
            longest_word = word;
        }
    }

    cout << longest_word;

    return 0;
}<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include "types.h"
#include "wiktdb.h"
#include "sparsearray.h"
#include "vectorize.h"

void loadData(const string& configFileName)
{
    MeaningExtractor::config.load(configFileName);

    WiktDB *wiktdb = new WiktDB();
    std::cout << "Loading DB..." << std::endl;
    wiktdb->loadDB(MeaningExtractor::config.wiktDBPath);
    std::cout << "DB loaded." << std::endl;

    MeaningExtractor::setDB(wiktdb);

    std::cout << "Preloading vectors..." << std::endl;
    MeaningExtractor::preloadVectors();
}

void writeMeanings(const string& oFileName)
{
    std::ofstream fMeanings;
    json meaningList = json::array();
    bool humanReadable = MeaningExtractor::config.humanReadable;

    fMeanings.open(oFileName);

    for (auto it = MeaningExtractor::reprCache.begin(); it != MeaningExtractor::reprCache.end(); ++it)
    {
        json meaning = json::object();

        meaning[FLD_ID] = it->first;
        meaning[FLD_TERM] = it->second.term;
        meaning[FLD_POS] = it->second.pos;
        meaning[FLD_DESCR] = it->second.descr;
        meaning[FLD_LANG] = it->second.lang;
        meaning[FLD_REPR] = MeaningExtractor::jsonRepr(it->second.repr, humanReadable);

        meaningList.push_back(meaning);
    }

    if (humanReadable)
        fMeanings <<  std::setw(2) << meaningList << std::endl;
    else
        fMeanings << meaningList;

    fMeanings.flush();
    fMeanings.close();
}

void writeVectors(const string& oFileName)
{
    std::ofstream fVectors;
    json meaningVectors = json::object();

    fVectors.open(oFileName);

    for (auto it = MeaningExtractor::reprCache.begin(); it != MeaningExtractor::reprCache.end(); ++it)
    {
        if (!meaningVectors.count(it->second.term))
        {
            meaningVectors[it->second.term] = json::array();
        }

        json meaning = json::object();
        meaning[FLD_ID] = it->first;
        meaning[FLD_POS] = it->second.pos;
        meaning["vec"] = MeaningExtractor::jsonRepr(it->second.repr, false);

        meaningVectors[it->second.term].push_back(meaning);
    }

    fVectors << meaningVectors;

    fVectors.flush();
    fVectors.close();
}

int main(int argc, char **argv)
{
    if (argc != 4)
    {
        std::cout << "Usage: " << argv[0] << " <config. filename> <output filename> <mode: (vectors|meanings)>" << std::endl;
    }
    else
    {
        string configFileName(argv[1]);
        string oFileName(argv[2]);
        string mode(argv[3]);

        loadData(configFileName);

        if (mode == "vectors")
            writeVectors(oFileName);
        else
            writeMeanings(oFileName);
    }

    return 0;
}
<commit_msg>- Added cosine distance matrix generation to gen_vectors.<commit_after>#include <iostream>
#include <fstream>
#include "types.h"
#include "wiktdb.h"
#include "sparsearray.h"
#include "vectorize.h"

void loadData(const string& configFileName)
{
    MeaningExtractor::config.load(configFileName);

    WiktDB *wiktdb = new WiktDB();
    std::cout << "Loading DB..." << std::endl;
    wiktdb->loadDB(MeaningExtractor::config.wiktDBPath);
    std::cout << "DB loaded." << std::endl;

    MeaningExtractor::setDB(wiktdb);

    std::cout << "Preloading vectors..." << std::endl;
    MeaningExtractor::preloadVectors();
}

void writeMeanings(const string& oFileName)
{
    std::ofstream fMeanings;
    json meaningList = json::array();
    bool humanReadable = MeaningExtractor::config.humanReadable;

    fMeanings.open(oFileName);

    for (auto it = MeaningExtractor::reprCache.begin(); it != MeaningExtractor::reprCache.end(); ++it)
    {
        json meaning = json::object();

        meaning[FLD_ID] = it->first;
        meaning[FLD_TERM] = it->second.term;
        meaning[FLD_POS] = it->second.pos;
        meaning[FLD_DESCR] = it->second.descr;
        meaning[FLD_LANG] = it->second.lang;
        meaning[FLD_REPR] = MeaningExtractor::jsonRepr(it->second.repr, humanReadable);

        meaningList.push_back(meaning);
    }

    if (humanReadable)
        fMeanings <<  std::setw(2) << meaningList << std::endl;
    else
        fMeanings << meaningList;

    fMeanings.flush();
    fMeanings.close();
}

void writeVectors(const string& oFileName)
{
    std::ofstream fVectors;
    json meaningVectors = json::object();

    fVectors.open(oFileName);

    for (auto it = MeaningExtractor::reprCache.begin(); it != MeaningExtractor::reprCache.end(); ++it)
    {
        if (!meaningVectors.count(it->second.term))
        {
            meaningVectors[it->second.term] = json::array();
        }

        json meaning = json::object();
        meaning[FLD_ID] = it->first;
        meaning[FLD_POS] = it->second.pos;
        meaning["vec"] = MeaningExtractor::jsonRepr(it->second.repr, false);

        meaningVectors[it->second.term].push_back(meaning);
    }

    fVectors << meaningVectors;

    fVectors.flush();
    fVectors.close();
}

void writeCosines(const string& oFileName)
{
    std::ofstream fCosines;
    std::ofstream fConcepts;
    json concepts = json::array();

    fCosines.open(oFileName + ".cosines.tsv");
    fConcepts.open(oFileName + ".concepts.json");

    ulong num_concepts = MeaningExtractor::reprCache.size();
    ulong count_done = 0;

    for (auto it1 = MeaningExtractor::reprCache.begin(); it1 != MeaningExtractor::reprCache.end(); ++it1)
    {
        json meaning = json::object();
        meaning[FLD_ID] = it->first;
        meaning[FLD_TERM] = it->second.term;
        meaning[FLD_POS] = it->second.pos;
        concepts.push_back(meaning);

        for (auto it2 = MeaningExtractor::reprCache.begin(); it2 != MeaningExtractor::reprCache.end(); ++it2)
        {
            float sim = 0;
            if (it1->first != it2->first)
                sim = MeaningExtractor::similarity(it1->second.term, it1->second.pos, it2->second.term, it2->second.pos, vector<string>(), 1);
            else
                sim = 1;

            if (it2 != MeaningExtractor::reprCache.begin())
                fCosines << "\t";

            fCosines << sim;
        }

        fCosines << std::endl;
    }

    fConcepts << concepts << std::endl;

    fConcepts.flush();
    fCosines.flush();
    fConcepts.close();
    fCosines.close();
}

int main(int argc, char **argv)
{
    if (argc != 4)
    {
        std::cout << "Usage: " << argv[0] << " <config. filename> <output filename> <mode: (vectors|meanings)>" << std::endl;
    }
    else
    {
        string configFileName(argv[1]);
        string oFileName(argv[2]);
        string mode(argv[3]);

        loadData(configFileName);

        if (mode == "vectors")
            writeVectors(oFileName);
        else
            writeMeanings(oFileName);
    }

    return 0;
}
<|endoftext|>


<commit_before>//*****************************************************************************
//*****************************************************************************

#include "xbridge.h"
#include "xbridgesession.h"
#include "xbridgesessionbtc.h"
// #include "xbridgesessionethereum.h"
// #include "xbridgesessionrpccommon.h"
#include "xbridgeapp.h"
#include "util/logger.h"
#include "util/settings.h"

#include <boost/date_time/posix_time/posix_time.hpp>

//*****************************************************************************
//*****************************************************************************
XBridge::XBridge()
    : m_timerIoWork(new boost::asio::io_service::work(m_timerIo))
    , m_timerThread(boost::bind(&boost::asio::io_service::run, &m_timerIo))
    , m_timer(m_timerIo, boost::posix_time::seconds(TIMER_INTERVAL))
{
    try
    {
        // services and threas
        for (int i = 0; i < THREAD_COUNT; ++i)
        {
            IoServicePtr ios(new boost::asio::io_service);

            m_services.push_back(ios);
            m_works.push_back(WorkPtr(new boost::asio::io_service::work(*ios)));

            m_threads.create_thread(boost::bind(&boost::asio::io_service::run, ios));
        }

        m_timer.async_wait(boost::bind(&XBridge::onTimer, this));

        // sessions
        XBridgeApp & app = XBridgeApp::instance();
        {
            Settings & s = settings();
            std::vector<std::string> wallets = s.exchangeWallets();
            for (std::vector<std::string>::iterator i = wallets.begin(); i != wallets.end(); ++i)
            {
                WalletParam wp;
                wp.currency                    = *i;
                wp.title                       = s.get<std::string>(*i + ".Title");
                wp.address                     = s.get<std::string>(*i + ".Address");
                wp.ip                          = s.get<std::string>(*i + ".Ip");
                wp.port                        = s.get<std::string>(*i + ".Port");
                wp.user                        = s.get<std::string>(*i + ".Username");
                wp.passwd                      = s.get<std::string>(*i + ".Password");
                wp.addrPrefix[0]               = s.get<int>(*i + ".AddressPrefix", 0);
                wp.scriptPrefix[0]             = s.get<int>(*i + ".ScriptPrefix", 0);
                wp.secretPrefix[0]             = s.get<int>(*i + ".SecretPrefix", 0);
                wp.COIN                        = s.get<uint64_t>(*i + ".COIN", 0);
                wp.txVersion                   = s.get<uint32_t>(*i + ".TxVersion", 1);
                wp.minTxFee                    = s.get<uint64_t>(*i + ".MinTxFee", 0);
                wp.feePerByte                  = s.get<uint64_t>(*i + ".FeePerByte", 200);
                wp.minAmount                   = s.get<uint64_t>(*i + ".MinimumAmount", 0);
                wp.dustAmount                  = s.get<uint64_t>(*i + ".DustAmount", 0);
                wp.method                      = s.get<std::string>(*i + ".CreateTxMethod");
                wp.isGetNewPubKeySupported     = s.get<bool>(*i + ".GetNewKeySupported", false);
                wp.isImportWithNoScanSupported = s.get<bool>(*i + ".ImportWithNoScanSupported", false);
                wp.blockTime                   = s.get<int>(*i + ".BlockTime", 0);

                if (wp.ip.empty() || wp.port.empty() ||
                    wp.user.empty() || wp.passwd.empty() ||
                    wp.COIN == 0 || wp.blockTime == 0)
                {
                    LOG() << "read wallet " << *i << " with empty parameters>";
                    continue;
                }
                else
                {
                    LOG() << "read wallet " << *i << " [" << wp.title << "] " << wp.ip
                          << ":" << wp.port; // << " COIN=" << wp.COIN;
                }

                XBridgeSessionPtr session;
                if (wp.method == "ETHER")
                {
                    assert(!"not implemented");
                    // session.reset(new XBridgeSessionEthereum(wp));
                }
                else if (wp.method == "BTC")
                {
                    session.reset(new XBridgeSessionBtc(wp));
                }
                else if (wp.method == "RPC")
                {
                    assert(!"not implemented");
                    // session.reset(new XBridgeSessionRpc(wp));
                }
                else
                {
                    session.reset(new XBridgeSession(wp));
                }
                if (session)
                {
                    app.addSession(session);
                }
            }
        }
    }
    catch (std::exception & e)
    {
        ERR() << e.what();
        ERR() << __FUNCTION__;
    }
}

//*****************************************************************************
//*****************************************************************************
void XBridge::run()
{
    m_threads.join_all();
}

//*****************************************************************************
//*****************************************************************************
void XBridge::stop()
{
    m_timer.cancel();
    m_timerIo.stop();
    m_timerIoWork.reset();
    m_timerThread.join();

//    for (IoServicePtr & i : m_services)
//    {
//        i->stop();
//    }
    for (WorkPtr & i : m_works)
    {
        i.reset();
    }

    m_threads.join_all();
}

//******************************************************************************
//******************************************************************************
void XBridge::onTimer()
{
    // DEBUG_TRACE();

    {
        m_services.push_back(m_services.front());
        m_services.pop_front();

        // XBridgeSessionPtr session(new XBridgeSession);
        XBridgeApp & app = XBridgeApp::instance();
        XBridgeSessionPtr session = app.serviceSession();

        IoServicePtr io = m_services.front();

        // call check expired transactions
        io->post(boost::bind(&XBridgeSession::checkFinishedTransactions, session));

        // send list of wallets (broadcast)
        // io->post(boost::bind(&XBridgeSession::sendListOfWallets, session));

        // send transactions list
        io->post(boost::bind(&XBridgeSession::sendListOfTransactions, session));

        // erase expired tx
        io->post(boost::bind(&XBridgeSession::eraseExpiredPendingTransactions, session));

        // check unconfirmed tx
        // io->post(boost::bind(&XBridgeSession::checkUnconfirmedTx, session));

        // resend addressbook
        // io->post(boost::bind(&XBridgeSession::resendAddressBook, session));
        io->post(boost::bind(&XBridgeSession::getAddressBook, session));

        // pending unprocessed packets
        {
            std::map<uint256, std::pair<std::string, XBridgePacketPtr> > map;
            {
                boost::mutex::scoped_lock l(XBridgeApp::m_ppLocker);
                map = XBridgeApp::m_pendingPackets;
                XBridgeApp::m_pendingPackets.clear();
            }

            for (const std::pair<uint256, std::pair<std::string, XBridgePacketPtr> > & item : map)
            {
                std::string      currency = std::get<0>(item.second);
                XBridgeSessionPtr s = app.sessionByCurrency(currency);
                if (!s)
                {
                    // no session. packet dropped
                    WARN() << "no session for <" << currency << ">, packet dropped " << __FUNCTION__;
                    continue;
                }

                XBridgePacketPtr packet   = std::get<1>(item.second);
                io->post(boost::bind(&XBridgeSession::processPacket, s, packet));
            }
        }
    }

    m_timer.expires_at(m_timer.expires_at() + boost::posix_time::seconds(TIMER_INTERVAL));
    m_timer.async_wait(boost::bind(&XBridge::onTimer, this));
}
<commit_msg>set dust amount = 3*minTxFee<commit_after>//*****************************************************************************
//*****************************************************************************

#include "xbridge.h"
#include "xbridgesession.h"
#include "xbridgesessionbtc.h"
// #include "xbridgesessionethereum.h"
// #include "xbridgesessionrpccommon.h"
#include "xbridgeapp.h"
#include "util/logger.h"
#include "util/settings.h"

#include <boost/date_time/posix_time/posix_time.hpp>

//*****************************************************************************
//*****************************************************************************
XBridge::XBridge()
    : m_timerIoWork(new boost::asio::io_service::work(m_timerIo))
    , m_timerThread(boost::bind(&boost::asio::io_service::run, &m_timerIo))
    , m_timer(m_timerIo, boost::posix_time::seconds(TIMER_INTERVAL))
{
    try
    {
        // services and threas
        for (int i = 0; i < THREAD_COUNT; ++i)
        {
            IoServicePtr ios(new boost::asio::io_service);

            m_services.push_back(ios);
            m_works.push_back(WorkPtr(new boost::asio::io_service::work(*ios)));

            m_threads.create_thread(boost::bind(&boost::asio::io_service::run, ios));
        }

        m_timer.async_wait(boost::bind(&XBridge::onTimer, this));

        // sessions
        XBridgeApp & app = XBridgeApp::instance();
        {
            Settings & s = settings();
            std::vector<std::string> wallets = s.exchangeWallets();
            for (std::vector<std::string>::iterator i = wallets.begin(); i != wallets.end(); ++i)
            {
                WalletParam wp;
                wp.currency                    = *i;
                wp.title                       = s.get<std::string>(*i + ".Title");
                wp.address                     = s.get<std::string>(*i + ".Address");
                wp.ip                          = s.get<std::string>(*i + ".Ip");
                wp.port                        = s.get<std::string>(*i + ".Port");
                wp.user                        = s.get<std::string>(*i + ".Username");
                wp.passwd                      = s.get<std::string>(*i + ".Password");
                wp.addrPrefix[0]               = s.get<int>(*i + ".AddressPrefix", 0);
                wp.scriptPrefix[0]             = s.get<int>(*i + ".ScriptPrefix", 0);
                wp.secretPrefix[0]             = s.get<int>(*i + ".SecretPrefix", 0);
                wp.COIN                        = s.get<uint64_t>(*i + ".COIN", 0);
                wp.txVersion                   = s.get<uint32_t>(*i + ".TxVersion", 1);
                wp.minTxFee                    = s.get<uint64_t>(*i + ".MinTxFee", 0);
                wp.feePerByte                  = s.get<uint64_t>(*i + ".FeePerByte", 200);
                wp.minAmount                   = s.get<uint64_t>(*i + ".MinimumAmount", 0);
                // wp.dustAmount                  = s.get<uint64_t>(*i + ".DustAmount", 0);
                wp.dustAmount                  = 3 * wp.minTxFee;
                wp.method                      = s.get<std::string>(*i + ".CreateTxMethod");
                wp.isGetNewPubKeySupported     = s.get<bool>(*i + ".GetNewKeySupported", false);
                wp.isImportWithNoScanSupported = s.get<bool>(*i + ".ImportWithNoScanSupported", false);
                wp.blockTime                   = s.get<int>(*i + ".BlockTime", 0);

                if (wp.ip.empty() || wp.port.empty() ||
                    wp.user.empty() || wp.passwd.empty() ||
                    wp.COIN == 0 || wp.blockTime == 0)
                {
                    LOG() << "read wallet " << *i << " with empty parameters>";
                    continue;
                }
                else
                {
                    LOG() << "read wallet " << *i << " [" << wp.title << "] " << wp.ip
                          << ":" << wp.port; // << " COIN=" << wp.COIN;
                }

                XBridgeSessionPtr session;
                if (wp.method == "ETHER")
                {
                    assert(!"not implemented");
                    // session.reset(new XBridgeSessionEthereum(wp));
                }
                else if (wp.method == "BTC")
                {
                    session.reset(new XBridgeSessionBtc(wp));
                }
                else if (wp.method == "RPC")
                {
                    assert(!"not implemented");
                    // session.reset(new XBridgeSessionRpc(wp));
                }
                else
                {
                    session.reset(new XBridgeSession(wp));
                }
                if (session)
                {
                    app.addSession(session);
                }
            }
        }
    }
    catch (std::exception & e)
    {
        ERR() << e.what();
        ERR() << __FUNCTION__;
    }
}

//*****************************************************************************
//*****************************************************************************
void XBridge::run()
{
    m_threads.join_all();
}

//*****************************************************************************
//*****************************************************************************
void XBridge::stop()
{
    m_timer.cancel();
    m_timerIo.stop();
    m_timerIoWork.reset();
    m_timerThread.join();

//    for (IoServicePtr & i : m_services)
//    {
//        i->stop();
//    }
    for (WorkPtr & i : m_works)
    {
        i.reset();
    }

    m_threads.join_all();
}

//******************************************************************************
//******************************************************************************
void XBridge::onTimer()
{
    // DEBUG_TRACE();

    {
        m_services.push_back(m_services.front());
        m_services.pop_front();

        // XBridgeSessionPtr session(new XBridgeSession);
        XBridgeApp & app = XBridgeApp::instance();
        XBridgeSessionPtr session = app.serviceSession();

        IoServicePtr io = m_services.front();

        // call check expired transactions
        io->post(boost::bind(&XBridgeSession::checkFinishedTransactions, session));

        // send list of wallets (broadcast)
        // io->post(boost::bind(&XBridgeSession::sendListOfWallets, session));

        // send transactions list
        io->post(boost::bind(&XBridgeSession::sendListOfTransactions, session));

        // erase expired tx
        io->post(boost::bind(&XBridgeSession::eraseExpiredPendingTransactions, session));

        // check unconfirmed tx
        // io->post(boost::bind(&XBridgeSession::checkUnconfirmedTx, session));

        // resend addressbook
        // io->post(boost::bind(&XBridgeSession::resendAddressBook, session));
        io->post(boost::bind(&XBridgeSession::getAddressBook, session));

        // pending unprocessed packets
        {
            std::map<uint256, std::pair<std::string, XBridgePacketPtr> > map;
            {
                boost::mutex::scoped_lock l(XBridgeApp::m_ppLocker);
                map = XBridgeApp::m_pendingPackets;
                XBridgeApp::m_pendingPackets.clear();
            }

            for (const std::pair<uint256, std::pair<std::string, XBridgePacketPtr> > & item : map)
            {
                std::string      currency = std::get<0>(item.second);
                XBridgeSessionPtr s = app.sessionByCurrency(currency);
                if (!s)
                {
                    // no session. packet dropped
                    WARN() << "no session for <" << currency << ">, packet dropped " << __FUNCTION__;
                    continue;
                }

                XBridgePacketPtr packet   = std::get<1>(item.second);
                io->post(boost::bind(&XBridgeSession::processPacket, s, packet));
            }
        }
    }

    m_timer.expires_at(m_timer.expires_at() + boost::posix_time::seconds(TIMER_INTERVAL));
    m_timer.async_wait(boost::bind(&XBridge::onTimer, this));
}
<|endoftext|>


<commit_before>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_GDT_FUNCTIONALS_L2_HH
#define DUNE_GDT_FUNCTIONALS_L2_HH

#include <dune/stuff/functions/interfaces.hh>
#include <dune/stuff/la/container/interfaces.hh>

#include <dune/gdt/localfunctional/codim0.hh>
#include <dune/gdt/localfunctional/codim1.hh>
#include <dune/gdt/localevaluation/product.hh>
#include <dune/gdt/assembler/system.hh>

#include "base.hh"

namespace Dune {
namespace GDT {
namespace Functionals {

template< class FunctionType, class VectorImp, class SpaceImp, class GridViewImp = typename SpaceImp::GridViewType >
class L2Volume;

namespace internal {

template< class FunctionType, class VectorImp, class SpaceImp, class GridViewImp >
class L2VolumeTraits
{
  static_assert(std::is_base_of< Stuff::LocalizableFunctionInterface< typename FunctionType::EntityType
                                                                    , typename FunctionType::DomainFieldType
                                                                    , FunctionType::dimDomain
                                                                    , typename FunctionType::RangeFieldType
                                                                    , FunctionType::dimRange
                                                                    , FunctionType::dimRangeCols >
                               , FunctionType >::value,
                "FunctionType has to be derived from Stuff::LocalizableFunctionInterface!");
  static_assert(std::is_base_of< SpaceInterface< typename SpaceImp::Traits >, SpaceImp >::value,
                "SpaceImp has to be derived from SpaceInterface!");
public:
  typedef L2Volume< FunctionType, VectorImp, SpaceImp, GridViewImp > derived_type;
  typedef VectorImp   VectorType;
  typedef SpaceImp    SpaceType;
  typedef GridViewImp GridViewType;
  typedef typename VectorType::ScalarType ScalarType;
}; // class L2VolumeTraits

} // namespace internal

template< class FunctionType, class VectorImp, class SpaceImp, class GridViewImp >
class L2Volume
  : public Functionals::VectorBased< internal::L2VolumeTraits< FunctionType, VectorImp, SpaceImp, GridViewImp > >
  , public SystemAssembler< SpaceImp, GridViewImp, SpaceImp >
{
  typedef Functionals::VectorBased< internal::L2VolumeTraits< FunctionType, VectorImp, SpaceImp, GridViewImp > >
      FunctionalBaseType;
  typedef SystemAssembler< SpaceImp, GridViewImp, SpaceImp > AssemblerBaseType;

  typedef LocalFunctional::Codim0Integral< LocalEvaluation::Product< FunctionType > > LocalFunctionalType;
  typedef LocalAssembler::Codim0Vector< LocalFunctionalType > LocalAssemblerType;

public:
  typedef internal::L2VolumeTraits< FunctionType, VectorImp, SpaceImp, GridViewImp > Traits;
  typedef typename Traits::VectorType VectorType;
  typedef typename Traits::SpaceType  SpaceType;
  typedef typename Traits::GridViewType GridViewType;

  L2Volume(const FunctionType& function, VectorType& vector, const SpaceType& space, const GridViewType& grid_view)
    : FunctionalBaseType(vector, space, grid_view)
    , AssemblerBaseType(space, grid_view)
    , function_(function)
    , local_functional_(function_)
    , local_assembler_(local_functional_)
  {
    this->add(local_assembler_, this->vector());
  }

  L2Volume(const FunctionType& function, VectorType& vector, const SpaceType& space)
    : FunctionalBaseType(vector, space)
    , AssemblerBaseType(space)
    , function_(function)
    , local_functional_(function_)
    , local_assembler_(local_functional_)
  {
    this->add(local_assembler_, this->vector());
  }

  virtual void assemble() DS_OVERRIDE DS_FINAL
  {
    AssemblerBaseType::assemble();
  }

private:
  const FunctionType& function_;
  const LocalFunctionalType local_functional_;
  const LocalAssemblerType local_assembler_;
}; // class L2Volume

template< class FunctionType, class VectorImp, class SpaceImp, class GridViewImp = typename SpaceImp::GridViewType >
class L2Face;

template< class FunctionType, class VectorImp, class SpaceImp, class GridViewImp >
class L2FaceTraits
{
  static_assert(std::is_base_of< Stuff::LocalizableFunctionInterface< typename FunctionType::EntityType
                                                                    , typename FunctionType::DomainFieldType
                                                                    , FunctionType::dimDomain
                                                                    , typename FunctionType::RangeFieldType
                                                                    , FunctionType::dimRange
                                                                    , FunctionType::dimRangeCols >
                               , FunctionType >::value,
                "FunctionType has to be derived from Stuff::LocalizableFunctionInterface!");
  static_assert(std::is_base_of< SpaceInterface< typename SpaceImp::Traits >, SpaceImp >::value,
                "SpaceImp has to be derived from SpaceInterface!");
public:
  typedef L2Face< FunctionType, VectorImp, SpaceImp, GridViewImp > derived_type;
  typedef VectorImp   VectorType;
  typedef SpaceImp    SpaceType;
  typedef GridViewImp GridViewType;
  typedef typename VectorType::ScalarType ScalarType;
  typedef LocalFunctional::Codim1Integral< LocalEvaluation::Product< FunctionType > > LocalFunctionalType;
}; // class L2FaceTraits

template< class FunctionType, class VectorImp, class SpaceImp, class GridViewImp >
class L2Face
  : public Functionals::AssemblableFaceBase< L2FaceTraits< FunctionType, VectorImp, SpaceImp, GridViewImp > >
{
  typedef Functionals::AssemblableFaceBase< L2FaceTraits< FunctionType, VectorImp, SpaceImp, GridViewImp > > BaseType;
public:
  typedef L2FaceTraits< FunctionType, VectorImp, SpaceImp, GridViewImp > Traits;

  typedef typename Traits::VectorType VectorType;
  typedef typename Traits::SpaceType  SpaceType;
  typedef typename Traits::GridViewType GridViewType;

private:
  typedef typename Traits::LocalFunctionalType LocalFunctionalType;

public:
  L2Face(const FunctionType& function, VectorType& vector, const SpaceType& space, const GridViewType& grid_view)
    : BaseType(vector, space, grid_view)
    , local_functional_(function)
  {}

  L2Face(const FunctionType& function, VectorType& vector, const SpaceType& space)
    : BaseType(vector, space)
    , local_functional_(function)
  {}

  virtual const LocalFunctionalType& local_functional() const DS_OVERRIDE DS_FINAL
  {
    return local_functional_;
  }

private:
  const LocalFunctionalType local_functional_;
}; // class L2Face

} // namespace Functionals
} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_FUNCTIONALS_L2_HH
<commit_msg>[functionals.l2] based L2Face on SystemAssembler<commit_after>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_GDT_FUNCTIONALS_L2_HH
#define DUNE_GDT_FUNCTIONALS_L2_HH

#include <dune/stuff/functions/interfaces.hh>
#include <dune/stuff/la/container/interfaces.hh>

#include <dune/gdt/localfunctional/codim0.hh>
#include <dune/gdt/localfunctional/codim1.hh>
#include <dune/gdt/localevaluation/product.hh>
#include <dune/gdt/assembler/system.hh>

#include "base.hh"

namespace Dune {
namespace GDT {
namespace Functionals {

template< class FunctionType, class VectorImp, class SpaceImp, class GridViewImp = typename SpaceImp::GridViewType >
class L2Volume;

namespace internal {

template< class FunctionType, class VectorImp, class SpaceImp, class GridViewImp >
class L2VolumeTraits
{
  static_assert(std::is_base_of< Stuff::LocalizableFunctionInterface< typename FunctionType::EntityType
                                                                    , typename FunctionType::DomainFieldType
                                                                    , FunctionType::dimDomain
                                                                    , typename FunctionType::RangeFieldType
                                                                    , FunctionType::dimRange
                                                                    , FunctionType::dimRangeCols >
                               , FunctionType >::value,
                "FunctionType has to be derived from Stuff::LocalizableFunctionInterface!");
  static_assert(std::is_base_of< SpaceInterface< typename SpaceImp::Traits >, SpaceImp >::value,
                "SpaceImp has to be derived from SpaceInterface!");
public:
  typedef L2Volume< FunctionType, VectorImp, SpaceImp, GridViewImp > derived_type;
  typedef VectorImp   VectorType;
  typedef SpaceImp    SpaceType;
  typedef GridViewImp GridViewType;
  typedef typename VectorType::ScalarType ScalarType;
}; // class L2VolumeTraits

} // namespace internal

template< class FunctionType, class VectorImp, class SpaceImp, class GridViewImp >
class L2Volume
  : public Functionals::VectorBased< internal::L2VolumeTraits< FunctionType, VectorImp, SpaceImp, GridViewImp > >
  , public SystemAssembler< SpaceImp, GridViewImp, SpaceImp >
{
  typedef Functionals::VectorBased< internal::L2VolumeTraits< FunctionType, VectorImp, SpaceImp, GridViewImp > >
      FunctionalBaseType;
  typedef SystemAssembler< SpaceImp, GridViewImp, SpaceImp > AssemblerBaseType;

  typedef LocalFunctional::Codim0Integral< LocalEvaluation::Product< FunctionType > > LocalFunctionalType;
  typedef LocalAssembler::Codim0Vector< LocalFunctionalType > LocalAssemblerType;

public:
  typedef internal::L2VolumeTraits< FunctionType, VectorImp, SpaceImp, GridViewImp > Traits;
  typedef typename Traits::VectorType VectorType;
  typedef typename Traits::SpaceType  SpaceType;
  typedef typename Traits::GridViewType GridViewType;

  L2Volume(const FunctionType& function, VectorType& vector, const SpaceType& space, const GridViewType& grid_view)
    : FunctionalBaseType(vector, space, grid_view)
    , AssemblerBaseType(space, grid_view)
    , function_(function)
    , local_functional_(function_)
    , local_assembler_(local_functional_)
  {
    this->add(local_assembler_, this->vector());
  }

  L2Volume(const FunctionType& function, VectorType& vector, const SpaceType& space)
    : FunctionalBaseType(vector, space)
    , AssemblerBaseType(space)
    , function_(function)
    , local_functional_(function_)
    , local_assembler_(local_functional_)
  {
    this->add(local_assembler_, this->vector());
  }

  virtual void assemble() DS_OVERRIDE DS_FINAL
  {
    AssemblerBaseType::assemble();
  }

private:
  const FunctionType& function_;
  const LocalFunctionalType local_functional_;
  const LocalAssemblerType local_assembler_;
}; // class L2Volume

template< class FunctionType, class VectorImp, class SpaceImp, class GridViewImp = typename SpaceImp::GridViewType >
class L2Face;

template< class FunctionType, class VectorImp, class SpaceImp, class GridViewImp >
class L2FaceTraits
{
  static_assert(std::is_base_of< Stuff::LocalizableFunctionInterface< typename FunctionType::EntityType
                                                                    , typename FunctionType::DomainFieldType
                                                                    , FunctionType::dimDomain
                                                                    , typename FunctionType::RangeFieldType
                                                                    , FunctionType::dimRange
                                                                    , FunctionType::dimRangeCols >
                               , FunctionType >::value,
                "FunctionType has to be derived from Stuff::LocalizableFunctionInterface!");
  static_assert(std::is_base_of< SpaceInterface< typename SpaceImp::Traits >, SpaceImp >::value,
                "SpaceImp has to be derived from SpaceInterface!");
public:
  typedef L2Face< FunctionType, VectorImp, SpaceImp, GridViewImp > derived_type;
  typedef VectorImp   VectorType;
  typedef SpaceImp    SpaceType;
  typedef GridViewImp GridViewType;
  typedef typename VectorType::ScalarType ScalarType;
}; // class L2FaceTraits

template< class FunctionType, class VectorImp, class SpaceImp, class GridViewImp >
class L2Face
  : public Functionals::VectorBased< L2FaceTraits< FunctionType, VectorImp, SpaceImp, GridViewImp > >
  , public SystemAssembler< SpaceImp, GridViewImp, SpaceImp >
{
  typedef Functionals::VectorBased< L2FaceTraits< FunctionType, VectorImp, SpaceImp, GridViewImp > >
      FunctionalBaseType;
  typedef SystemAssembler< SpaceImp, GridViewImp, SpaceImp > AssemblerBaseType;

  typedef LocalFunctional::Codim1Integral< LocalEvaluation::Product< FunctionType > > LocalFunctionalType;
  typedef LocalAssembler::Codim1Vector< LocalFunctionalType > LocalAssemblerType;
public:
  typedef L2FaceTraits< FunctionType, VectorImp, SpaceImp, GridViewImp > Traits;

  typedef typename Traits::VectorType VectorType;
  typedef typename Traits::SpaceType  SpaceType;
  typedef typename Traits::GridViewType GridViewType;

  L2Face(const FunctionType& function,
         VectorType& vector,
         const SpaceType& space,
         const GridViewType& grid_view,
         GDT::ApplyOn::WhichIntersection< GridViewType >* which_intersections
            = new GDT::ApplyOn::AllIntersections< GridViewType >())
    : FunctionalBaseType(vector, space, grid_view)
    , AssemblerBaseType(space, grid_view)
    , function_(function)
    , local_functional_(function_)
    , local_assembler_(local_functional_)
  {
    this->add(local_assembler_, *(this->vector()), which_intersections);
  }

  L2Face(const FunctionType& function,
         VectorType& vector,
         const SpaceType& space,
         GDT::ApplyOn::WhichIntersection< GridViewType >* which_intersections
            = new GDT::ApplyOn::AllIntersections< GridViewType >())
    : FunctionalBaseType(vector, space)
    , AssemblerBaseType(space)
    , function_(function)
    , local_functional_(function_)
    , local_assembler_(local_functional_)
  {
    this->add(local_assembler_, this->vector(), which_intersections);
  }

  virtual void assemble() DS_OVERRIDE DS_FINAL
  {
    AssemblerBaseType::assemble();
  }

private:
  const FunctionType& function_;
  const LocalFunctionalType local_functional_;
  const LocalAssemblerType local_assembler_;
}; // class L2Face

} // namespace Functionals
} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_FUNCTIONALS_L2_HH
<|endoftext|>


<commit_before>// Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
#include "../bse.hh"
#include "v8bse.cc"
#include <node.h>

// v8pp binding for Bse
static V8stub *bse_v8stub = NULL;

// register bindings and start Bse
static void
v8bse_register_module (v8::Local<v8::Object> exports)
{
  assert (bse_v8stub == NULL);
  // start Bse
  Bse::String bseoptions = Bse::string_format ("debug-extensions=%d", 0);
  Bse::init_async (NULL, NULL, "BEAST", Bse::string_split (bseoptions, ":"));
  // register v8stub
  v8::Isolate *const isolate = v8::Isolate::GetCurrent();
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
  bse_v8stub = new V8stub (isolate);
  v8::Maybe<bool> ok = exports->SetPrototype (context, bse_v8stub->module_.new_instance());
  assert (ok.FromJust() == true);
}

// node.js registration
NODE_MODULE (v8bse, v8bse_register_module);
<commit_msg>V8BSE: hook up v8bse with the GLib or libuv event loops<commit_after>// Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
#include "../bse.hh"
#include "v8bse.cc"
#include <node.h>
#include <uv.h>

// v8pp binding for Bse
static V8stub *bse_v8stub = NULL;

// event loop integration
static uv_poll_t                         bse_uv_watcher;
static Rapicorn::Aida::ClientConnectionP bse_client_connection;
static Bse::ServerH                      bse_server;

// register bindings and start Bse
static void
v8bse_register_module (v8::Local<v8::Object> exports)
{
  assert (bse_v8stub == NULL);
  v8::Isolate *const isolate = v8::Isolate::GetCurrent();
  v8::HandleScope scope (isolate);

  // start Bse
  Bse::String bseoptions = Bse::string_format ("debug-extensions=%d", 0);
  Bse::init_async (NULL, NULL, "BEAST", Bse::string_split (bseoptions, ":"));

  // fetch server handle
  assert (bse_server == NULL);
  assert (bse_client_connection == NULL);
  bse_client_connection = Bse::init_server_connection();
  assert (bse_client_connection != NULL);
  bse_server = Bse::init_server_instance();
  assert (bse_server != NULL);

  // hook BSE connection into libuv event loop
  uv_loop_t *loop = uv_default_loop();
  uv_poll_init (loop, &bse_uv_watcher, bse_client_connection->notify_fd());
  auto bse_uv_callback = [] (uv_poll_t *watcher, int status, int revents) {
    if (bse_client_connection && bse_client_connection->pending())
      bse_client_connection->dispatch();
  };
  uv_poll_start (&bse_uv_watcher, UV_READABLE, bse_uv_callback);

  // hook BSE connection into GLib event loop
  Bse::AidaGlibSource *source = Bse::AidaGlibSource::create (bse_client_connection.get());
  g_source_set_priority (source, G_PRIORITY_DEFAULT);
  g_source_attach (source, g_main_context_default());

  // register v8stub
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
  bse_v8stub = new V8stub (isolate);
  v8::Local<v8::Object> module_instance = bse_v8stub->module_.new_instance();
  v8::Maybe<bool> ok = exports->SetPrototype (context, module_instance);
  assert (ok.FromJust() == true);
}

// node.js registration
NODE_MODULE (v8bse, v8bse_register_module);
<|endoftext|>


<commit_before>/*
  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

#include "ts/ts.h"
#include "ts/remap.h"
#include "ink_defs.h"

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>

static const char PLUGIN_NAME[] = "conf_remap";

// This makes the plugin depend on the version of traffic server installed, but that's
// OK, since this plugin is distributed only with the "core" (it's a core piece).
#define MAX_OVERRIDABLE_CONFIGS TS_CONFIG_LAST_ENTRY

// Class to hold a set of configurations (one for each remap rule instance)
struct RemapConfigs
{
  struct Item {
    TSOverridableConfigKey _name;
    TSRecordDataType _type;
    TSRecordData _data;
    int _data_len; // Used when data is a string
  };

  RemapConfigs()
    : _current(0)
  {
    memset(_items, 0, sizeof(_items));
  };

  bool parse_file(const char *fn);

  Item _items[MAX_OVERRIDABLE_CONFIGS];
  int _current;
};

// Helper functionfor the parser
inline TSRecordDataType
str_to_datatype(const char* str)
{
  TSRecordDataType type = TS_RECORDDATATYPE_NULL;

  if (!str || !*str)
    return TS_RECORDDATATYPE_NULL;

  if (!strcmp(str, "INT")) {
    type = TS_RECORDDATATYPE_INT;
  } else if (!strcmp(str, "STRING")) {
    type = TS_RECORDDATATYPE_STRING;
  }

  return type;
}

// Config file parser, somewhat borrowed from P_RecCore.i
bool
RemapConfigs::parse_file(const char* fn)
{
  int line_num = 0;
  TSFile file;
  char buf[8192];
  TSOverridableConfigKey name;
  TSRecordDataType type, expected_type;

  if (!fn || ('\0' == *fn))
    return false;

  if (NULL == (file = TSfopen(fn, "r"))) {
    TSError("%s: could not open config file %s", PLUGIN_NAME, fn);
    return false;
  }

  TSDebug(PLUGIN_NAME, "loading configuration file %s", fn);

  while (NULL != TSfgets(file, buf, sizeof(buf))) {
    char *ln, *tok;
    char *s = buf;

    ++line_num; // First line is #1 ...
    while (isspace(*s))
      ++s;
    tok = strtok_r(s, " \t", &ln);

    // check for blank lines and comments
    if ((!tok) || (tok && ('#' == *tok)))
      continue;

    if (strncmp(tok, "CONFIG", 6)) {
      TSError("%s: file %s, line %d: non-CONFIG line encountered", PLUGIN_NAME, fn, line_num);
      continue;
    }

    // Find the configuration name
    tok = strtok_r(NULL, " \t", &ln);
    if (TSHttpTxnConfigFind(tok, -1, &name, &expected_type) != TS_SUCCESS) {
      TSError("%s: file %s, line %d: no records.config name given", PLUGIN_NAME, fn, line_num);
      continue;
    }

    // Find the type (INT or STRING only)
    tok = strtok_r(NULL, " \t", &ln);
    if (TS_RECORDDATATYPE_NULL == (type = str_to_datatype(tok))) {
      TSError("%s: file %s, line %d: only INT and STRING types supported", PLUGIN_NAME, fn, line_num);
      continue;
    }

    if (type != expected_type) {
      TSError("%s: file %s, line %d: mismatch between provide data type, and expected type", PLUGIN_NAME, fn, line_num);
      continue;
    }

    // Find the value (which depends on the type above)
    if (ln) {
      while (isspace(*ln))
        ++ln;
      if ('\0' == *ln) {
        tok = NULL;
      } else {
        tok = ln;
        while (*ln != '\0')
          ++ln;
        --ln;
        while (isspace(*ln) && (ln > tok))
          --ln;
        ++ln;
        *ln = '\0';
      }
    } else {
      tok = NULL;
    }
    if (!tok) {
      TSError("%s: file %s, line %d: the configuration must provide a value", PLUGIN_NAME, fn, line_num);
      continue;
    }

    // Now store the new config
    switch (type) {
    case TS_RECORDDATATYPE_INT:
      _items[_current]._data.rec_int = strtoll(tok, NULL, 10);
      break;
    case TS_RECORDDATATYPE_STRING:
      _items[_current]._data.rec_string = TSstrdup(tok);
      _items[_current]._data_len = strlen(tok);
      break;
    default:
      TSError("%s: file %s, line %d: type not support (unheard of)", PLUGIN_NAME, fn, line_num);
      continue;
      break;
    }
    _items[_current]._name = name;
    _items[_current]._type = type;
    ++_current;
  }

  TSfclose(file);
  return (_current > 0);
}

///////////////////////////////////////////////////////////////////////////////
// Initialize the plugin as a remap plugin.
//
TSReturnCode
TSRemapInit(TSRemapInterface* api_info, char *errbuf, int errbuf_size)
{
  if (!api_info) {
    TSstrlcpy(errbuf, "[TSRemapInit] - Invalid TSRemapInterface argument", errbuf_size);
    return TS_ERROR;
  }

  if (api_info->size < sizeof(TSRemapInterface)) {
    TSstrlcpy(errbuf, "[TSRemapInit] - Incorrect size of TSRemapInterface structure", errbuf_size);
    return TS_ERROR;
  }

  TSDebug(PLUGIN_NAME, "remap plugin is successfully initialized");
  return TS_SUCCESS;                     /* success */
}

TSReturnCode
TSRemapNewInstance(int argc, char* argv[], void** ih, char* /* errbuf ATS_UNUSED */, int /* errbuf_size ATS_UNUSED */)
{
  if (argc < 3) {
    TSError("Unable to create remap instance, need configuration file");
    return TS_ERROR;
  } else {
    RemapConfigs* conf = new(RemapConfigs);

    for (int i=2; i < argc; ++i) {
      if (conf->parse_file(argv[i])) {
        *ih = static_cast<void*>(conf);
      } else {
        *ih = NULL;
        delete conf;
      }
    }
  }

  return TS_SUCCESS;
}

void
TSRemapDeleteInstance(void* ih)
{
  RemapConfigs* conf = static_cast<RemapConfigs*>(ih);

  for (int ix=0; ix < conf->_current; ++ix) {
    if (TS_RECORDDATATYPE_STRING == conf->_items[ix]._type)
      TSfree(conf->_items[ix]._data.rec_string);
  }

  delete conf;
}

///////////////////////////////////////////////////////////////////////////////
// Main entry point when used as a remap plugin.
//
TSRemapStatus
TSRemapDoRemap(void* ih, TSHttpTxn rh, TSRemapRequestInfo * /* rri ATS_UNUSED */)
{
  if (NULL != ih) {
    RemapConfigs* conf = static_cast<RemapConfigs*>(ih);
    TSHttpTxn txnp = static_cast<TSHttpTxn>(rh);

    for (int ix=0; ix < conf->_current; ++ix) {
      switch (conf->_items[ix]._type) {
      case TS_RECORDDATATYPE_INT:
        TSHttpTxnConfigIntSet(txnp, conf->_items[ix]._name, conf->_items[ix]._data.rec_int);
        TSDebug(PLUGIN_NAME, "Setting config id %d to %" PRId64"", conf->_items[ix]._name, conf->_items[ix]._data.rec_int);
        break;
      case TS_RECORDDATATYPE_STRING:
        TSHttpTxnConfigStringSet(txnp, conf->_items[ix]._name, conf->_items[ix]._data.rec_string, conf->_items[ix]._data_len);
        TSDebug(PLUGIN_NAME, "Setting config id %d to %s", conf->_items[ix]._name, conf->_items[ix]._data.rec_string);
        break;
      default:
        break; // Error ?
      }
    }
  }

  return TSREMAP_NO_REMAP; // This plugin never rewrites anything.
}

/*
  local variables:
  mode: C++
  indent-tabs-mode: nil
  c-basic-offset: 2
  c-comment-only-line-offset: 0
  c-file-offsets: ((statement-block-intro . +)
  (label . 0)
  (statement-cont . +)
  (innamespace . 0))
  end:

  Indent with: /usr/bin/indent -ncs -nut -npcs -l 120 logstats.cc
*/
<commit_msg>config_remap: accept file paths relative to SYSCONFIGDIR<commit_after>/*
  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

#include "ts/ts.h"
#include "ts/remap.h"
#include "ink_defs.h"

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <string>

static const char PLUGIN_NAME[] = "conf_remap";

// This makes the plugin depend on the version of traffic server installed, but that's
// OK, since this plugin is distributed only with the "core" (it's a core piece).
#define MAX_OVERRIDABLE_CONFIGS TS_CONFIG_LAST_ENTRY

// Class to hold a set of configurations (one for each remap rule instance)
struct RemapConfigs
{
  struct Item {
    TSOverridableConfigKey _name;
    TSRecordDataType _type;
    TSRecordData _data;
    int _data_len; // Used when data is a string
  };

  RemapConfigs()
    : _current(0)
  {
    memset(_items, 0, sizeof(_items));
  };

  bool parse_file(const char *filename);

  Item _items[MAX_OVERRIDABLE_CONFIGS];
  int _current;
};

// Helper functionfor the parser
inline TSRecordDataType
str_to_datatype(const char* str)
{
  TSRecordDataType type = TS_RECORDDATATYPE_NULL;

  if (!str || !*str)
    return TS_RECORDDATATYPE_NULL;

  if (!strcmp(str, "INT")) {
    type = TS_RECORDDATATYPE_INT;
  } else if (!strcmp(str, "STRING")) {
    type = TS_RECORDDATATYPE_STRING;
  }

  return type;
}

// Config file parser, somewhat borrowed from P_RecCore.i
bool
RemapConfigs::parse_file(const char* filename)
{
  int line_num = 0;
  TSFile file;
  char buf[8192];
  TSOverridableConfigKey name;
  TSRecordDataType type, expected_type;

  std::string path;

  if (!filename || ('\0' == *filename))
    return false;

  if (*filename == '/') {
    // Absolute path, just use it.
    path = filename;
  } else {
    // Relative path. Make it relative to the configuration directory.
    path = TSConfigDirGet();
    path += "/";
    path += filename;
  }

  if (NULL == (file = TSfopen(path.c_str(), "r"))) {
    TSError("%s: could not open config file %s", PLUGIN_NAME, path.c_str());
    return false;
  }

  TSDebug(PLUGIN_NAME, "loading configuration file %s", path.c_str());

  while (NULL != TSfgets(file, buf, sizeof(buf))) {
    char *ln, *tok;
    char *s = buf;

    ++line_num; // First line is #1 ...
    while (isspace(*s))
      ++s;
    tok = strtok_r(s, " \t", &ln);

    // check for blank lines and comments
    if ((!tok) || (tok && ('#' == *tok)))
      continue;

    if (strncmp(tok, "CONFIG", 6)) {
      TSError("%s: file %s, line %d: non-CONFIG line encountered", PLUGIN_NAME, path.c_str(), line_num);
      continue;
    }

    // Find the configuration name
    tok = strtok_r(NULL, " \t", &ln);
    if (TSHttpTxnConfigFind(tok, -1, &name, &expected_type) != TS_SUCCESS) {
      TSError("%s: file %s, line %d: no records.config name given", PLUGIN_NAME, path.c_str(), line_num);
      continue;
    }

    // Find the type (INT or STRING only)
    tok = strtok_r(NULL, " \t", &ln);
    if (TS_RECORDDATATYPE_NULL == (type = str_to_datatype(tok))) {
      TSError("%s: file %s, line %d: only INT and STRING types supported", PLUGIN_NAME, path.c_str(), line_num);
      continue;
    }

    if (type != expected_type) {
      TSError("%s: file %s, line %d: mismatch between provide data type, and expected type", PLUGIN_NAME, path.c_str(), line_num);
      continue;
    }

    // Find the value (which depends on the type above)
    if (ln) {
      while (isspace(*ln))
        ++ln;
      if ('\0' == *ln) {
        tok = NULL;
      } else {
        tok = ln;
        while (*ln != '\0')
          ++ln;
        --ln;
        while (isspace(*ln) && (ln > tok))
          --ln;
        ++ln;
        *ln = '\0';
      }
    } else {
      tok = NULL;
    }
    if (!tok) {
      TSError("%s: file %s, line %d: the configuration must provide a value", PLUGIN_NAME, path.c_str(), line_num);
      continue;
    }

    // Now store the new config
    switch (type) {
    case TS_RECORDDATATYPE_INT:
      _items[_current]._data.rec_int = strtoll(tok, NULL, 10);
      break;
    case TS_RECORDDATATYPE_STRING:
      _items[_current]._data.rec_string = TSstrdup(tok);
      _items[_current]._data_len = strlen(tok);
      break;
    default:
      TSError("%s: file %s, line %d: type not support (unheard of)", PLUGIN_NAME, path.c_str(), line_num);
      continue;
      break;
    }
    _items[_current]._name = name;
    _items[_current]._type = type;
    ++_current;
  }

  TSfclose(file);
  return (_current > 0);
}

///////////////////////////////////////////////////////////////////////////////
// Initialize the plugin as a remap plugin.
//
TSReturnCode
TSRemapInit(TSRemapInterface* api_info, char *errbuf, int errbuf_size)
{
  if (!api_info) {
    TSstrlcpy(errbuf, "[TSRemapInit] - Invalid TSRemapInterface argument", errbuf_size);
    return TS_ERROR;
  }

  if (api_info->size < sizeof(TSRemapInterface)) {
    TSstrlcpy(errbuf, "[TSRemapInit] - Incorrect size of TSRemapInterface structure", errbuf_size);
    return TS_ERROR;
  }

  TSDebug(PLUGIN_NAME, "remap plugin is successfully initialized");
  return TS_SUCCESS;                     /* success */
}

TSReturnCode
TSRemapNewInstance(int argc, char* argv[], void** ih, char* /* errbuf ATS_UNUSED */, int /* errbuf_size ATS_UNUSED */)
{
  if (argc < 3) {
    TSError("Unable to create remap instance, need configuration file");
    return TS_ERROR;
  } else {
    RemapConfigs* conf = new(RemapConfigs);

    for (int i=2; i < argc; ++i) {
      if (conf->parse_file(argv[i])) {
        *ih = static_cast<void*>(conf);
      } else {
        *ih = NULL;
        delete conf;
      }
    }
  }

  return TS_SUCCESS;
}

void
TSRemapDeleteInstance(void* ih)
{
  RemapConfigs* conf = static_cast<RemapConfigs*>(ih);

  for (int ix=0; ix < conf->_current; ++ix) {
    if (TS_RECORDDATATYPE_STRING == conf->_items[ix]._type)
      TSfree(conf->_items[ix]._data.rec_string);
  }

  delete conf;
}

///////////////////////////////////////////////////////////////////////////////
// Main entry point when used as a remap plugin.
//
TSRemapStatus
TSRemapDoRemap(void* ih, TSHttpTxn rh, TSRemapRequestInfo * /* rri ATS_UNUSED */)
{
  if (NULL != ih) {
    RemapConfigs* conf = static_cast<RemapConfigs*>(ih);
    TSHttpTxn txnp = static_cast<TSHttpTxn>(rh);

    for (int ix=0; ix < conf->_current; ++ix) {
      switch (conf->_items[ix]._type) {
      case TS_RECORDDATATYPE_INT:
        TSHttpTxnConfigIntSet(txnp, conf->_items[ix]._name, conf->_items[ix]._data.rec_int);
        TSDebug(PLUGIN_NAME, "Setting config id %d to %" PRId64"", conf->_items[ix]._name, conf->_items[ix]._data.rec_int);
        break;
      case TS_RECORDDATATYPE_STRING:
        TSHttpTxnConfigStringSet(txnp, conf->_items[ix]._name, conf->_items[ix]._data.rec_string, conf->_items[ix]._data_len);
        TSDebug(PLUGIN_NAME, "Setting config id %d to %s", conf->_items[ix]._name, conf->_items[ix]._data.rec_string);
        break;
      default:
        break; // Error ?
      }
    }
  }

  return TSREMAP_NO_REMAP; // This plugin never rewrites anything.
}

/*
  local variables:
  mode: C++
  indent-tabs-mode: nil
  c-basic-offset: 2
  c-comment-only-line-offset: 0
  c-file-offsets: ((statement-block-intro . +)
  (label . 0)
  (statement-cont . +)
  (innamespace . 0))
  end:

  Indent with: /usr/bin/indent -ncs -nut -npcs -l 120 logstats.cc
*/
<|endoftext|>