<commit_before>#if 0
set -e -x
g++ -g3 -DCHILDPROCESSMANAGERTESTMAIN childprocessmanager.cc LockWait.cc -o cpm -lpthread
exit 0
#endif

/* -*- Mode:c++; eval:(c-set-style "BSD"); c-basic-offset:4; indent-tabs-mode:nil; tab-width:8 -*- */

#include "childprocessmanager.h"
#include "bufprintf.h"

#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/wait.h>
#include <pthread.h>

#include <iostream>

using namespace std;

namespace ChildProcessManager {

/************************ Handle ******************************/

Handle :: Handle(void)
{
    pipe(fromChildPipe);
    pipe(toChildPipe);
    open = false;
    fds[0] = fromChildPipe[0];
    fds[1] = toChildPipe[1];
}

Handle :: ~Handle(void)
{
    open = false;
#define CLOSEFD(fd) if (fd != -1) { close(fd); fd = -1; }
    CLOSEFD(fromChildPipe[0]);
    CLOSEFD(fromChildPipe[1]);
    CLOSEFD(toChildPipe[0]);
    CLOSEFD(toChildPipe[1]);
}

bool
Handle :: createChild(void)
{
    return Manager::instance()->createChild(this);
}

/************************ Manager ******************************/

Manager * Manager::_instance = NULL;

Manager * Manager::instance(void)
{
    if (_instance == NULL)
        _instance = new Manager();
    return _instance;
}

void
Manager :: cleanup(void)
{
    if (_instance != NULL)
    {
        delete _instance;
        _instance = NULL;
    }
}

Manager :: Manager(void)
{
    struct sigaction sa;
    sa.sa_handler = &Manager::sigChildHandler;
    sigfillset(&sa.sa_mask);
    sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
    sigaction(SIGCHLD, &sa, &sigChildOact);
    pipe(signalFds);
    pipe(rebuildFds);
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    pthread_create(&notifyThreadId, &attr,
                   &Manager::notifyThread, (void*) this);
    pthread_attr_destroy(&attr);
}

Manager :: ~Manager(void)
{
    char dummy = 2; // code 2 means die
    write(rebuildFds[1], &dummy, 1);
    sigaction(SIGCHLD, &sigChildOact, NULL);
    close(signalFds[0]);
    close(signalFds[1]);
    close(rebuildFds[0]);
    close(rebuildFds[1]);
}

bool
Manager :: createChild(Handle *handle)
{
    int forkErrorPipe[2];
    pipe(forkErrorPipe);

    // since we're forking for the purpose of
    // only exec, use vfork instead of fork.
    // it is more efficient. there are restrictions
    // to what the child can do (before exec) though.
    handle->pid = vfork();
    if (handle->pid < 0)
    {
        int e = errno;
        cerr << "fork: " << e << ": " << strerror(errno) << endl;
        return false;
    }

    if (handle->pid == 0)
    {
        // child

        // move pipe ends we do use to the
        // fd numbers where they're used by
        // the child.

        dup2(handle->toChildPipe[0], 0);
        dup2(handle->fromChildPipe[1], 1);
        dup2(handle->fromChildPipe[1], 2);

        // don't allow the child to inhert any
        // "interesting" file descriptors.
        for (int i = 3; i < sysconf(_SC_OPEN_MAX); i++)
            if (i != forkErrorPipe[1])
                close(i);

        // mark the 'fork error' pipe as close-on-exec,
        // so if the exec succeeds, the parent gets a zero
        // read, but if it fails, it gets a 1-read.
        fcntl(forkErrorPipe[1], F_SETFD, FD_CLOEXEC);

        execvp(handle->cmd[0], (char *const*)handle->cmd.data());

        // dont print stuff! we're vforked, that can screw
        // up the parent process' address space.

        // send the errno to parent.
        int e = errno;
        write(forkErrorPipe[1], &e, sizeof(int));

        // call _exit because it isn't correct for a vforked
        // child to call the atexit handlers, that can screw
        // up crap in the parent.
        _exit(99);
    }
    //parent

    // close pipe ends we don't use.
    CLOSEFD(handle->fromChildPipe[1]);
    CLOSEFD(handle->toChildPipe[0]);
    close(forkErrorPipe[1]);

    bool ret = false;
    int e;
    int cc = read(forkErrorPipe[0], &e, sizeof(e));
    close(forkErrorPipe[0]);
    if (cc == 0)
    {
        // zero read means the pipe was closed-on-exec,
        // so child success.
        handle->open = true;
        {
            WaitUtil::Lock key(&handleLock);
            openHandles[handle->pid] = handle;
        } // key destroyed here
        // wake up notify thread so it knows to
        // rebuild its fd_sets to include the
        // new handle.
        char dummy = 1; // code 1 means rebuild
        (void) write(rebuildFds[1], &dummy, 1);
        ret = true;
    }
    else
    {
        // nonzero read means exec failed in the child.
        cerr << "execvp " << handle->cmd[0]
             << " failed with error " << e << ": "
             << strerror(e) << endl;
    }

    return ret;
}

//static
void
Manager :: sigChildHandler(int s)
{
    struct signalMsg msg;
    do {
        msg.pid = waitpid(/*wait for any child*/-1,
                          &msg.status, WNOHANG);

        if (msg.pid > 0)
        {
            if (0) // debug
            {
                Bufprintf<80>  bufp;
                bufp.print("sig handler got pid %d died, status %d\n",
                           msg.pid, msg.status);
                bufp.write(1);
            }
            if (_instance != NULL)
                // dont do any data structure manipulations here;
                // it is difficult to mutex between threads and
                // signal handlers. (it can be done with sigprocmask but
                // that is expensive.) instead send a message to the
                // notify thread and let it deal with it in thread
                // context.
                (void) write(_instance->signalFds[1], &msg, sizeof(msg));
        }

    } while (msg.pid > 0);
}

//static
void *
Manager :: notifyThread(void *arg)
{
    Manager * mgr = (Manager *) arg;
    mgr->_notifyThread();
    return NULL;
}

void
Manager :: _notifyThread(void)
{
    bool done = false;
    std::vector<Handle*> handles;
    char buffer[4096];
    int cc;
    fd_set rfds;
    int maxfd;
    HandleMap::iterator it;
    Handle * h;
    struct signalMsg msg;
    char dummy;

    while (!done)
    {
        FD_ZERO(&rfds);
        maxfd = signalFds[0];
        FD_SET(signalFds[0], &rfds);
        if (maxfd < rebuildFds[0])
            maxfd = rebuildFds[0];
        FD_SET(rebuildFds[0], &rfds);

        { // add fds for all open handles to the fd_set.
            WaitUtil::Lock key(&handleLock);
            for (it = openHandles.begin();
                 it != openHandles.end();
                 it++)
            {
                h = it->second;
                if (h->open)
                {
                    if (maxfd < h->fds[0])
                        maxfd = h->fds[0];
                    FD_SET(h->fds[0], &rfds);
                }
            }
        } // key destroyed here

        select(maxfd+1, &rfds, NULL, NULL, NULL);

        if (FD_ISSET(rebuildFds[0], &rfds))
        {
            if (read(rebuildFds[0], &dummy, 1) != 1)
                done = true;
            else
                if (dummy == 2) // die code
                    // must be the manager destructor
                    done = true;

            if (0) // debug
            {
                Bufprintf<80> bufp;
                bufp.print("thread awakened on rebuild fd, done = %d\n",
                           done);
                bufp.write(1);
            }
            // otherwise this is just meant to make sure we rebuild
            // our fd_sets because the openHandles map has changed.
        }
        if (!done && FD_ISSET(signalFds[0], &rfds))
        {
            // the sigchld handler has sent us a pid and status.
            cc = read(signalFds[0], &msg, sizeof(msg));
            if (cc <= 0)
                done = true;
            else
            {
                if (0) // debug
                {
                    Bufprintf<80> bufp;
                    bufp.print("got msg pid %d died status %d\n",
                               msg.pid, msg.status);
                    bufp.write(1);
                }
                WaitUtil::Lock key(&handleLock);
                it = openHandles.find(msg.pid);
                if (it != openHandles.end())
                {
                    h = it->second;
                    h->processExited(msg.status);
                    h->open = false;
                    openHandles.erase(it);
                }
            } // key destroyed here
        }
        if (!done)
        { // check all open handles
            // dont hold the key while calling h->handleOutput.
            // build the list of all handles that need servicing
            // first, then release the key.
            {
                WaitUtil::Lock key(&handleLock);
                for (it = openHandles.begin();
                     it != openHandles.end();
                     it++)
                {
                    h = it->second;
                    if (FD_ISSET(h->fds[0], &rfds))
                        handles.push_back(h);
                }
            } // key destroyed here
            for (int ind = 0; ind < handles.size(); ind++)
            {
                h = handles[ind];
                cc = read(h->fds[0], buffer, sizeof(buffer));
                if (cc > 0)
                    // call user's virtual method to handle the data.
                    h->handleOutput(buffer, cc);
            }
            handles.clear();
        }
    }
}

}; /* namespace ChildProcessManager */

#ifdef CHILDPROCESSMANAGERTESTMAIN

class TestHandle : public ChildProcessManager::Handle {
    int inst;
public:
    TestHandle(int _inst) : inst(_inst) {
        if (0) // debug
        {
            Bufprintf<80> bufp;
            bufp.print("constructing testhandle inst %d\n", inst);
            bufp.write(1);
        }
        if (inst == 1)
            cmd.push_back("cat");
        else
            cmd.push_back("sh");
        cmd.push_back(NULL);
    }
    virtual ~TestHandle(void) {
        if (0) // debug
        {
            Bufprintf<80> bufp;
            bufp.print("~TestHandle destructor inst %d\n", inst);
            bufp.write(1);
        }
    }
    /*virtual*/ void handleOutput(const char *buffer, size_t len) {
        cout << "data from inst " << inst << endl;
        write(1, buffer, len);
    }
    /*virtual*/ void processExited(int status) {
        cout << "processExited called for inst " << inst << endl;
    }
};

int
main()
{

    // sigpipe is a fucking douchefucker. fuck him.
    struct sigaction sa;
    sa.sa_handler = SIG_IGN;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;//SA_RESTART;
    sigaction(SIGPIPE, &sa, NULL);

    cout << "my pid is " << getpid() << endl;
    ChildProcessManager::Manager::instance();
    {
        TestHandle hdl1(1);
        TestHandle hdl2(2);
        hdl1.createChild();
        hdl2.createChild();
        char buf[256];
        int cc;

        while (hdl1.getOpen() || hdl2.getOpen())
        {
            cc = read(0, buf, sizeof(buf));
            if  (cc == 0)
                break;
            hdl1.writeInput(buf, cc);
            hdl2.writeInput(buf, cc);
        }
        if (hdl1.getOpen())
            hdl1.closeChildInput();
        if (hdl2.getOpen())
            hdl2.closeChildInput();
        while (hdl1.getOpen() && hdl2.getOpen())
            usleep(1);
    }
    ChildProcessManager::Manager::cleanup();
    return 0;
}

#endif
<commit_msg>childprocessmanager shouldn't use vfork because vfork considered dangerous<commit_after>#if 0
set -e -x
g++ -g3 -DCHILDPROCESSMANAGERTESTMAIN childprocessmanager.cc LockWait.cc -o cpm -lpthread
exit 0
#endif

/* -*- Mode:c++; eval:(c-set-style "BSD"); c-basic-offset:4; indent-tabs-mode:nil; tab-width:8 -*- */

#include "childprocessmanager.h"
#include "bufprintf.h"

#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/wait.h>
#include <pthread.h>

#include <iostream>

using namespace std;

namespace ChildProcessManager {

/************************ Handle ******************************/

Handle :: Handle(void)
{
    pipe(fromChildPipe);
    pipe(toChildPipe);
    open = false;
    fds[0] = fromChildPipe[0];
    fds[1] = toChildPipe[1];
}

Handle :: ~Handle(void)
{
    open = false;
#define CLOSEFD(fd) if (fd != -1) { close(fd); fd = -1; }
    CLOSEFD(fromChildPipe[0]);
    CLOSEFD(fromChildPipe[1]);
    CLOSEFD(toChildPipe[0]);
    CLOSEFD(toChildPipe[1]);
}

bool
Handle :: createChild(void)
{
    return Manager::instance()->createChild(this);
}

/************************ Manager ******************************/

Manager * Manager::_instance = NULL;

Manager * Manager::instance(void)
{
    if (_instance == NULL)
        _instance = new Manager();
    return _instance;
}

void
Manager :: cleanup(void)
{
    if (_instance != NULL)
    {
        delete _instance;
        _instance = NULL;
    }
}

Manager :: Manager(void)
{
    struct sigaction sa;
    sa.sa_handler = &Manager::sigChildHandler;
    sigfillset(&sa.sa_mask);
    sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
    sigaction(SIGCHLD, &sa, &sigChildOact);
    pipe(signalFds);
    pipe(rebuildFds);
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    pthread_create(&notifyThreadId, &attr,
                   &Manager::notifyThread, (void*) this);
    pthread_attr_destroy(&attr);
}

Manager :: ~Manager(void)
{
    char dummy = 2; // code 2 means die
    write(rebuildFds[1], &dummy, 1);
    sigaction(SIGCHLD, &sigChildOact, NULL);
    close(signalFds[0]);
    close(signalFds[1]);
    close(rebuildFds[0]);
    close(rebuildFds[1]);
}

bool
Manager :: createChild(Handle *handle)
{
    int forkErrorPipe[2];
    pipe(forkErrorPipe);

    // google "vfork considered dangerous". the article on
    // EWONTFIX is particularly informative.
    handle->pid = fork();
    if (handle->pid < 0)
    {
        int e = errno;
        cerr << "fork: " << e << ": " << strerror(errno) << endl;
        return false;
    }

    if (handle->pid == 0)
    {
        // child

        // move pipe ends we do use to the
        // fd numbers where they're used by
        // the child.

        dup2(handle->toChildPipe[0], 0);
        dup2(handle->fromChildPipe[1], 1);
        dup2(handle->fromChildPipe[1], 2);

        // don't allow the child to inhert any
        // "interesting" file descriptors. note this
        // also closes all the pipe ends we don't use in the child.
        for (int i = 3; i < sysconf(_SC_OPEN_MAX); i++)
            if (i != forkErrorPipe[1])
                close(i);

        // mark the 'fork error' pipe as close-on-exec,
        // so if the exec succeeds, the parent gets a zero
        // read, but if it fails, it gets a 1-read.
        fcntl(forkErrorPipe[1], F_SETFD, FD_CLOEXEC);

        execvp(handle->cmd[0], (char *const*)handle->cmd.data());

        // dont print stuff! fork is weird, don't trust anything
        // to work.

        // send the errno to parent.
        int e = errno;
        write(forkErrorPipe[1], &e, sizeof(int));

        // call _exit because we dont want to call any atexit handlers.
        _exit(99);
    }
    //parent

    // close pipe ends we don't use.
    CLOSEFD(handle->fromChildPipe[1]);
    CLOSEFD(handle->toChildPipe[0]);
    close(forkErrorPipe[1]);

    bool ret = false;
    int e;
    int cc = read(forkErrorPipe[0], &e, sizeof(e));
    close(forkErrorPipe[0]);
    if (cc == 0)
    {
        // zero read means the pipe was closed-on-exec,
        // so child success.
        handle->open = true;
        {
            WaitUtil::Lock key(&handleLock);
            openHandles[handle->pid] = handle;
        } // key destroyed here
        // wake up notify thread so it knows to
        // rebuild its fd_sets to include the
        // new handle.
        char dummy = 1; // code 1 means rebuild
        (void) write(rebuildFds[1], &dummy, 1);
        ret = true;
    }
    else
    {
        // nonzero read means exec failed in the child.
        cerr << "execvp " << handle->cmd[0]
             << " failed with error " << e << ": "
             << strerror(e) << endl;
    }

    return ret;
}

//static
void
Manager :: sigChildHandler(int s)
{
    struct signalMsg msg;
    do {
        msg.pid = waitpid(/*wait for any child*/-1,
                          &msg.status, WNOHANG);

        if (msg.pid > 0)
        {
            if (0) // debug
            {
                Bufprintf<80>  bufp;
                bufp.print("sig handler got pid %d died, status %d\n",
                           msg.pid, msg.status);
                bufp.write(1);
            }
            if (_instance != NULL)
                // dont do any data structure manipulations here;
                // it is difficult to mutex between threads and
                // signal handlers. (it can be done with sigprocmask but
                // that is expensive.) instead send a message to the
                // notify thread and let it deal with it in thread
                // context.
                (void) write(_instance->signalFds[1], &msg, sizeof(msg));
        }

    } while (msg.pid > 0);
}

//static
void *
Manager :: notifyThread(void *arg)
{
    Manager * mgr = (Manager *) arg;
    mgr->_notifyThread();
    return NULL;
}

void
Manager :: _notifyThread(void)
{
    bool done = false;
    std::vector<Handle*> handles;
    char buffer[4096];
    int cc;
    fd_set rfds;
    int maxfd;
    HandleMap::iterator it;
    Handle * h;
    struct signalMsg msg;
    char dummy;

    while (!done)
    {
        FD_ZERO(&rfds);
        maxfd = signalFds[0];
        FD_SET(signalFds[0], &rfds);
        if (maxfd < rebuildFds[0])
            maxfd = rebuildFds[0];
        FD_SET(rebuildFds[0], &rfds);

        { // add fds for all open handles to the fd_set.
            WaitUtil::Lock key(&handleLock);
            for (it = openHandles.begin();
                 it != openHandles.end();
                 it++)
            {
                h = it->second;
                if (h->open)
                {
                    if (maxfd < h->fds[0])
                        maxfd = h->fds[0];
                    FD_SET(h->fds[0], &rfds);
                }
            }
        } // key destroyed here

        select(maxfd+1, &rfds, NULL, NULL, NULL);

        if (FD_ISSET(rebuildFds[0], &rfds))
        {
            if (read(rebuildFds[0], &dummy, 1) != 1)
                done = true;
            else
                if (dummy == 2) // die code
                    // must be the manager destructor
                    done = true;

            if (0) // debug
            {
                Bufprintf<80> bufp;
                bufp.print("thread awakened on rebuild fd, done = %d\n",
                           done);
                bufp.write(1);
            }
            // otherwise this is just meant to make sure we rebuild
            // our fd_sets because the openHandles map has changed.
        }
        if (!done && FD_ISSET(signalFds[0], &rfds))
        {
            // the sigchld handler has sent us a pid and status.
            cc = read(signalFds[0], &msg, sizeof(msg));
            if (cc <= 0)
                done = true;
            else
            {
                if (0) // debug
                {
                    Bufprintf<80> bufp;
                    bufp.print("got msg pid %d died status %d\n",
                               msg.pid, msg.status);
                    bufp.write(1);
                }
                WaitUtil::Lock key(&handleLock);
                it = openHandles.find(msg.pid);
                if (it != openHandles.end())
                {
                    h = it->second;
                    h->processExited(msg.status);
                    h->open = false;
                    openHandles.erase(it);
                }
            } // key destroyed here
        }
        if (!done)
        { // check all open handles
            // dont hold the key while calling h->handleOutput.
            // build the list of all handles that need servicing
            // first, then release the key.
            {
                WaitUtil::Lock key(&handleLock);
                for (it = openHandles.begin();
                     it != openHandles.end();
                     it++)
                {
                    h = it->second;
                    if (FD_ISSET(h->fds[0], &rfds))
                        handles.push_back(h);
                }
            } // key destroyed here
            for (int ind = 0; ind < handles.size(); ind++)
            {
                h = handles[ind];
                cc = read(h->fds[0], buffer, sizeof(buffer));
                if (cc > 0)
                    // call user's virtual method to handle the data.
                    h->handleOutput(buffer, cc);
            }
            handles.clear();
        }
    }
}

}; /* namespace ChildProcessManager */

#ifdef CHILDPROCESSMANAGERTESTMAIN

class TestHandle : public ChildProcessManager::Handle {
    int inst;
public:
    TestHandle(int _inst) : inst(_inst) {
        if (0) // debug
        {
            Bufprintf<80> bufp;
            bufp.print("constructing testhandle inst %d\n", inst);
            bufp.write(1);
        }
        if (inst == 1)
            cmd.push_back("cat");
        else
            cmd.push_back("sh");
        cmd.push_back(NULL);
    }
    virtual ~TestHandle(void) {
        if (0) // debug
        {
            Bufprintf<80> bufp;
            bufp.print("~TestHandle destructor inst %d\n", inst);
            bufp.write(1);
        }
    }
    /*virtual*/ void handleOutput(const char *buffer, size_t len) {
        cout << "data from inst " << inst << endl;
        write(1, buffer, len);
    }
    /*virtual*/ void processExited(int status) {
        cout << "processExited called for inst " << inst << endl;
    }
};

int
main()
{

    // sigpipe is a fucking douchefucker. fuck him.
    struct sigaction sa;
    sa.sa_handler = SIG_IGN;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;//SA_RESTART;
    sigaction(SIGPIPE, &sa, NULL);

    cout << "my pid is " << getpid() << endl;
    ChildProcessManager::Manager::instance();
    {
        TestHandle hdl1(1);
        TestHandle hdl2(2);
        hdl1.createChild();
        hdl2.createChild();
        char buf[256];
        int cc;

        while (hdl1.getOpen() || hdl2.getOpen())
        {
            cc = read(0, buf, sizeof(buf));
            if  (cc == 0)
                break;
            hdl1.writeInput(buf, cc);
            hdl2.writeInput(buf, cc);
        }
        if (hdl1.getOpen())
            hdl1.closeChildInput();
        if (hdl2.getOpen())
            hdl2.closeChildInput();
        while (hdl1.getOpen() && hdl2.getOpen())
            usleep(1);
    }
    ChildProcessManager::Manager::cleanup();
    return 0;
}

#endif
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015, Cryptonomex, Inc.
 * All rights reserved.
 *
 * This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
 * the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
 * are permitted until September 8, 2015, provided that the following conditions are met:
 *
 * 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <graphene/chain/database.hpp>

#include <graphene/chain/operation_history_object.hpp>
#include <graphene/chain/protocol/fee_schedule.hpp>

#include <functional>
#include <iostream>

namespace graphene { namespace chain {

database::database()
{
   initialize_indexes();
   initialize_evaluators();
}

database::~database(){
   if( _pending_block_session )
      _pending_block_session->commit();
}

void database::reindex(fc::path data_dir, const genesis_state_type& initial_allocation)
{ try {
   ilog( "reindexing blockchain" );
   wipe(data_dir, false);
   open(data_dir, [&initial_allocation]{return initial_allocation;});

   auto start = fc::time_point::now();
   auto last_block = _block_id_to_block.last();
   if( !last_block ) {
      elog( "!no last block" );
      edump((last_block));
      return;
   }

   const auto last_block_num = last_block->block_num();

   ilog( "Replaying blocks..." );
   _undo_db.disable();
   for( uint32_t i = 1; i <= last_block_num; ++i )
   {
      if( i % 2000 == 0 ) std::cerr << "   " << double(i*100)/last_block_num << "%   "<<i << " of " <<last_block_num<<"   \n";
      apply_block(*_block_id_to_block.fetch_by_number(i), skip_witness_signature |
                                skip_transaction_signatures |
                                skip_transaction_dupe_check |
                                skip_tapos_check |
                                skip_witness_schedule_check |
                                skip_authority_check);
   }
   _undo_db.enable();
   auto end = fc::time_point::now();
   ilog( "Done reindexing, elapsed time: ${t} sec", ("t",double((end-start).count())/1000000.0 ) );
} FC_CAPTURE_AND_RETHROW( (data_dir) ) }

void database::wipe(const fc::path& data_dir, bool include_blocks)
{
   ilog("Wiping database", ("include_blocks", include_blocks));
   close();
   object_database::wipe(data_dir);
   if( include_blocks )
      fc::remove_all( data_dir / "database" );
}

void database::open(
   const fc::path& data_dir,
   std::function<genesis_state_type()> genesis_loader )
   elog( "Open Database" );
{
   try
   {
      object_database::open(data_dir);

      _block_id_to_block.open(data_dir / "database" / "block_num_to_block");

      if( !find(global_property_id_type()) )
         init_genesis(genesis_loader());

      _pending_block.previous  = head_block_id();
      _pending_block.timestamp = head_block_time();

      auto last_block = _block_id_to_block.last();
      if( last_block.valid() )
         _fork_db.start_block( *last_block );

      idump((last_block->id())(last_block->block_num())(head_block_id())(head_block_num()));
      FC_ASSERT( last_block->id() == head_block_id() );
   }
   FC_CAPTURE_AND_RETHROW( (data_dir) )
}

void database::close(uint32_t blocks_to_rewind)
{
   _pending_block_session.reset();

   for(uint32_t i = 0; i < blocks_to_rewind && head_block_num() > 0; ++i)
      pop_block();

   // pop all of the blocks that we can given our undo history, this should
   // throw when there is no more undo history to pop
   try { while( true ) { elog("pop"); pop_block(); } } catch (...){}

   object_database::flush();
   object_database::close();

   if( _block_id_to_block.is_open() )
      _block_id_to_block.close();

   _fork_db.reset();
}

} }
<commit_msg>Fix build error<commit_after>/*
 * Copyright (c) 2015, Cryptonomex, Inc.
 * All rights reserved.
 *
 * This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
 * the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
 * are permitted until September 8, 2015, provided that the following conditions are met:
 *
 * 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <graphene/chain/database.hpp>

#include <graphene/chain/operation_history_object.hpp>
#include <graphene/chain/protocol/fee_schedule.hpp>

#include <functional>
#include <iostream>

namespace graphene { namespace chain {

database::database()
{
   initialize_indexes();
   initialize_evaluators();
}

database::~database(){
   if( _pending_block_session )
      _pending_block_session->commit();
}

void database::reindex(fc::path data_dir, const genesis_state_type& initial_allocation)
{ try {
   ilog( "reindexing blockchain" );
   wipe(data_dir, false);
   open(data_dir, [&initial_allocation]{return initial_allocation;});

   auto start = fc::time_point::now();
   auto last_block = _block_id_to_block.last();
   if( !last_block ) {
      elog( "!no last block" );
      edump((last_block));
      return;
   }

   const auto last_block_num = last_block->block_num();

   ilog( "Replaying blocks..." );
   _undo_db.disable();
   for( uint32_t i = 1; i <= last_block_num; ++i )
   {
      if( i % 2000 == 0 ) std::cerr << "   " << double(i*100)/last_block_num << "%   "<<i << " of " <<last_block_num<<"   \n";
      apply_block(*_block_id_to_block.fetch_by_number(i), skip_witness_signature |
                                skip_transaction_signatures |
                                skip_transaction_dupe_check |
                                skip_tapos_check |
                                skip_witness_schedule_check |
                                skip_authority_check);
   }
   _undo_db.enable();
   auto end = fc::time_point::now();
   ilog( "Done reindexing, elapsed time: ${t} sec", ("t",double((end-start).count())/1000000.0 ) );
} FC_CAPTURE_AND_RETHROW( (data_dir) ) }

void database::wipe(const fc::path& data_dir, bool include_blocks)
{
   ilog("Wiping database", ("include_blocks", include_blocks));
   close();
   object_database::wipe(data_dir);
   if( include_blocks )
      fc::remove_all( data_dir / "database" );
}

void database::open(
   const fc::path& data_dir,
   std::function<genesis_state_type()> genesis_loader )
{
   elog( "Open Database" );
   try
   {
      object_database::open(data_dir);

      _block_id_to_block.open(data_dir / "database" / "block_num_to_block");

      if( !find(global_property_id_type()) )
         init_genesis(genesis_loader());

      _pending_block.previous  = head_block_id();
      _pending_block.timestamp = head_block_time();

      auto last_block = _block_id_to_block.last();
      if( last_block.valid() )
         _fork_db.start_block( *last_block );

      idump((last_block->id())(last_block->block_num())(head_block_id())(head_block_num()));
      FC_ASSERT( last_block->id() == head_block_id() );
   }
   FC_CAPTURE_AND_RETHROW( (data_dir) )
}

void database::close(uint32_t blocks_to_rewind)
{
   _pending_block_session.reset();

   for(uint32_t i = 0; i < blocks_to_rewind && head_block_num() > 0; ++i)
      pop_block();

   // pop all of the blocks that we can given our undo history, this should
   // throw when there is no more undo history to pop
   try { while( true ) { elog("pop"); pop_block(); } } catch (...){}

   object_database::flush();
   object_database::close();

   if( _block_id_to_block.is_open() )
      _block_id_to_block.close();

   _fork_db.reset();
}

} }
<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////////////
//
// File: Misc.cpp
//
// For more information, please see: http://www.nektar.info
//
// The MIT License
//
// Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
// Department of Aeronautics, Imperial College London (UK), and Scientific
// Computing and Imaging Institute, University of Utah (USA).
//
// License for the specific language governing rights and limitations under
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// Description: Miscellaneous solver routines.
//
///////////////////////////////////////////////////////////////////////////////

#include <utility>
#include <vector>

#include <boost/lexical_cast.hpp>
#include <SolverUtils/Core/Misc.h>

using namespace std;

namespace Nektar {
namespace SolverUtils {
    /**
     * Adds an item to a SummaryList
     */
    void AddSummaryItem(
            SummaryList& l,
            const std::string& name,
            const std::string& value)
    {
        l.push_back(std::make_pair<std::string, std::string>(name, value));
    }

    /// Adds a summary item to the summary info list
    void AddSummaryItem(
            SummaryList& l,
            const std::string& name,
            const int& value)
    {
        l.push_back(std::make_pair<std::string, std::string>(name, boost::lexical_cast<std::string>(value)));
    }

    /// Adds a summary item to the summary info list
    void AddSummaryItem(
            SummaryList& l,
            const std::string& name,
            const NekDouble& value)
    {
        l.push_back(std::make_pair<std::string, std::string>(name, boost::lexical_cast<std::string>(value)));
    }

}
}
<commit_msg>Fix for outputting of doubles in summary<commit_after>///////////////////////////////////////////////////////////////////////////////
//
// File: Misc.cpp
//
// For more information, please see: http://www.nektar.info
//
// The MIT License
//
// Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
// Department of Aeronautics, Imperial College London (UK), and Scientific
// Computing and Imaging Institute, University of Utah (USA).
//
// License for the specific language governing rights and limitations under
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// Description: Miscellaneous solver routines.
//
///////////////////////////////////////////////////////////////////////////////

#include <utility>
#include <vector>
#include <iomanip>

#include <boost/lexical_cast.hpp>
#include <SolverUtils/Core/Misc.h>

using namespace std;

namespace Nektar {
namespace SolverUtils {
    /**
     * Adds an item to a SummaryList
     */
    void AddSummaryItem(
            SummaryList& l,
            const std::string& name,
            const std::string& value)
    {
        l.push_back(std::make_pair<std::string, std::string>(name, value));
    }

    /// Adds a summary item to the summary info list
    void AddSummaryItem(
            SummaryList& l,
            const std::string& name,
            const int& value)
    {
        l.push_back(std::make_pair<std::string, std::string>(name, boost::lexical_cast<std::string>(value)));
    }

    /// Adds a summary item to the summary info list
    void AddSummaryItem(
            SummaryList& l,
            const std::string& name,
            const NekDouble& value)
    {
        ostringstream ss;
        ss << value;
        l.push_back(std::make_pair<std::string, std::string>(name, ss.str()));
    }

}
}
<|endoftext|>


<commit_before>/**
 * Templated default configurations
 */

const char* platform_filter_template = R"(
          - name: envoy.filters.http.platform_bridge
            typed_config:
              "@type": type.googleapis.com/envoymobile.extensions.filters.http.platform_bridge.PlatformBridge
              platform_filter_name: {{ platform_filter_name }}
)";

const char* native_filter_template = R"(
          - name: {{ native_filter_name }}
            typed_config: {{ native_filter_typed_config }}
)";

const char* route_cache_reset_filter_template = R"(
          - name: envoy.filters.http.route_cache_reset
            typed_config:
              "@type": type.googleapis.com/envoymobile.extensions.filters.http.route_cache_reset.RouteCacheReset
)";

const char* fake_remote_listener_template = R"(
  - name: fake_remote_listener
    address:
      socket_address: { protocol: TCP, address: 127.0.0.1, port_value: 10101 }
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          stat_prefix: remote_hcm
          route_config:
            name: remote_route
            virtual_hosts:
            - name: remote_service
              domains: ["*"]
              routes:
{{ direct_responses }}
          http_filters:
          - name: envoy.router
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
)";

const char* fake_remote_cluster_template = R"(
  - name: fake_remote
    connect_timeout: 1.0s
    type: STATIC
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: fake_remote
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address: { address: 127.0.0.1, port_value: 10101 }
)";

const char* stats_sink_template = R"(
stats_sinks:
  - name: envoy.metrics_service
    typed_config:
      "@type": type.googleapis.com/envoy.config.metrics.v3.MetricsServiceConfig
      transport_api_version: V3
      report_counters_as_deltas: true
      emit_tags_as_labels: true
      grpc_service:
        envoy_grpc:
          cluster_name: stats
)";

const char* config_template = R"(
static_resources:
  listeners:
{{ fake_remote_listener }}
  - name: base_api_listener
    address:
      socket_address:
        protocol: TCP
        address: 0.0.0.0
        port_value: 10000
    per_connection_buffer_limit_bytes: 10485760 # 10MB
    api_listener:
      api_listener:
        "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
        stat_prefix: hcm
        route_config:
          name: api_router
          virtual_hosts:
            - name: api
              include_attempt_count_in_response: true
              virtual_clusters: {{ virtual_clusters }}
              domains:
                - "*"
              routes:
{{ fake_cluster_matchers }}
                - match:
                    prefix: "/"
                  route:
                    cluster_header: x-envoy-mobile-cluster
                    retry_policy:
                      retry_back_off:
                        base_interval: 0.25s
                        max_interval: 60s
        http_filters:
{{ platform_filter_chain }}
          - name: envoy.filters.http.local_error
            typed_config:
              "@type": type.googleapis.com/envoymobile.extensions.filters.http.local_error.LocalError
{{ native_filter_chain }}
          - name: envoy.filters.http.dynamic_forward_proxy
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.dynamic_forward_proxy.v3.FilterConfig
              dns_cache_config: &dns_cache_config
                name: dynamic_forward_proxy_cache_config
                # TODO: Support IPV6 https://github.com/lyft/envoy-mobile/issues/1022
                dns_lookup_family: V4_ONLY
                dns_refresh_rate: {{ dns_refresh_rate_seconds }}s
                dns_failure_refresh_rate:
                  base_interval: {{ dns_failure_refresh_rate_seconds_base }}s
                  max_interval: {{ dns_failure_refresh_rate_seconds_max }}s
          # TODO: make this configurable for users.
          - name: envoy.filters.http.decompressor
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.decompressor.v3.Decompressor
              decompressor_library:
                name: gzip
                typed_config:
                  "@type": type.googleapis.com/envoy.extensions.compression.gzip.decompressor.v3.Gzip
                  # Maximum window bits to allow for any stream to be decompressed. Optimally this
                  # would be set to 0. According to the zlib manual this would allow the decompressor
                  # to use the window bits in the zlib header to perform the decompression.
                  # Unfortunately, the proto field constraint makes this impossible currently.
                  window_bits: 15
              request_direction_config:
                common_config:
                  enabled:
                    default_value: false
                    runtime_key: request_decompressor_enabled
{{ route_reset_filter }}
          - name: envoy.router
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
  clusters:
{{ fake_remote_cluster }}
  - name: base
    connect_timeout: {{ connect_timeout_seconds }}s
    lb_policy: CLUSTER_PROVIDED
    cluster_type:
      name: envoy.clusters.dynamic_forward_proxy
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.clusters.dynamic_forward_proxy.v3.ClusterConfig
        dns_cache_config: *dns_cache_config
    transport_socket: &base_transport_socket
      name: envoy.transport_sockets.tls
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
        common_tls_context:
          validation_context:
            trusted_ca:
              inline_string: |
)"
#include "certificates.inc"

                              R"(
    upstream_connection_options: &upstream_opts
      tcp_keepalive:
        keepalive_interval: 8
        keepalive_probes: 1
        keepalive_time: 2
    circuit_breakers: &circuit_breakers_settings
      thresholds:
        - priority: DEFAULT
          # n.b: with mobile clients there are scenarios where all concurrent requests might be
          # retries (e.g., when the phone goes offline). Therefore, Envoy Mobile allows for the same
          # amount of concurrency for retries as the default value for concurrency for requests.
          # This configuration uses the default for max concurrent requests (1024) because there is
          # no reasonable scenario where a mobile client should have even close to that many concurrent
          # requests.
          #
          # `max_retries` could be used but maintainers advised against it, as there are plans to
          # deprecate that setting.
          # https://github.com/lyft/envoy-mobile/pull/811#issuecomment-619169529.
          retry_budget:
            budget_percent:
              value: 100
            min_retry_concurrency: 1024
  - name: base_wlan
    connect_timeout: {{ connect_timeout_seconds }}s
    lb_policy: CLUSTER_PROVIDED
    cluster_type:
      name: envoy.clusters.dynamic_forward_proxy
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.clusters.dynamic_forward_proxy.v3.ClusterConfig
        dns_cache_config: *dns_cache_config
    transport_socket: *base_transport_socket
    upstream_connection_options: *upstream_opts
    circuit_breakers: *circuit_breakers_settings
  - name: base_wwan
    connect_timeout: {{ connect_timeout_seconds }}s
    lb_policy: CLUSTER_PROVIDED
    cluster_type:
      name: envoy.clusters.dynamic_forward_proxy
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.clusters.dynamic_forward_proxy.v3.ClusterConfig
        dns_cache_config: *dns_cache_config
    transport_socket: *base_transport_socket
    upstream_connection_options: *upstream_opts
    circuit_breakers: *circuit_breakers_settings
  - name: base_clear
    connect_timeout: {{ connect_timeout_seconds }}s
    lb_policy: CLUSTER_PROVIDED
    cluster_type:
      name: envoy.clusters.dynamic_forward_proxy
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.clusters.dynamic_forward_proxy.v3.ClusterConfig
        dns_cache_config: *dns_cache_config
    transport_socket:
      name: envoy.transport_sockets.raw_buffer
    upstream_connection_options: *upstream_opts
    circuit_breakers: *circuit_breakers_settings
  - name: base_wlan_clear
    connect_timeout: {{ connect_timeout_seconds }}s
    lb_policy: CLUSTER_PROVIDED
    cluster_type:
      name: envoy.clusters.dynamic_forward_proxy
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.clusters.dynamic_forward_proxy.v3.ClusterConfig
        dns_cache_config: *dns_cache_config
    transport_socket:
      name: envoy.transport_sockets.raw_buffer
    upstream_connection_options: *upstream_opts
    circuit_breakers: *circuit_breakers_settings
  - name: base_wwan_clear
    connect_timeout: {{ connect_timeout_seconds }}s
    lb_policy: CLUSTER_PROVIDED
    cluster_type:
      name: envoy.clusters.dynamic_forward_proxy
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.clusters.dynamic_forward_proxy.v3.ClusterConfig
        dns_cache_config: *dns_cache_config
    transport_socket:
      name: envoy.transport_sockets.raw_buffer
    upstream_connection_options: *upstream_opts
    circuit_breakers: *circuit_breakers_settings
  - name: base_h2
    http2_protocol_options: {}
    connect_timeout: {{ connect_timeout_seconds }}s
    lb_policy: CLUSTER_PROVIDED
    cluster_type:
      name: envoy.clusters.dynamic_forward_proxy
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.clusters.dynamic_forward_proxy.v3.ClusterConfig
        dns_cache_config: *dns_cache_config
    transport_socket: *base_transport_socket
    upstream_connection_options: *upstream_opts
    circuit_breakers: *circuit_breakers_settings
  - name: base_wlan_h2
    http2_protocol_options: {}
    connect_timeout: {{ connect_timeout_seconds }}s
    lb_policy: CLUSTER_PROVIDED
    cluster_type:
      name: envoy.clusters.dynamic_forward_proxy
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.clusters.dynamic_forward_proxy.v3.ClusterConfig
        dns_cache_config: *dns_cache_config
    transport_socket: *base_transport_socket
    upstream_connection_options: *upstream_opts
    circuit_breakers: *circuit_breakers_settings
  - name: base_wwan_h2
    http2_protocol_options: {}
    connect_timeout: {{ connect_timeout_seconds }}s
    lb_policy: CLUSTER_PROVIDED
    cluster_type:
      name: envoy.clusters.dynamic_forward_proxy
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.clusters.dynamic_forward_proxy.v3.ClusterConfig
        dns_cache_config: *dns_cache_config
    transport_socket: *base_transport_socket
    upstream_connection_options: *upstream_opts
    circuit_breakers: *circuit_breakers_settings
  - name: stats
    connect_timeout: {{ connect_timeout_seconds }}s
    dns_refresh_rate: {{ dns_refresh_rate_seconds }}s
    http2_protocol_options: {}
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: stats
      endpoints:
        - lb_endpoints:
            - endpoint:
                address:
                  socket_address: {address: {{ stats_domain }}, port_value: 443}
    transport_socket: *base_transport_socket
    type: LOGICAL_DNS
stats_flush_interval: {{ stats_flush_interval_seconds }}s
{{ stats_sink }}
stats_config:
  stats_matcher:
    inclusion_list:
      patterns:
        - safe_regex:
            google_re2: {}
            regex: '^cluster\.[\w]+?\.upstream_cx_[\w]+'
        - safe_regex:
            google_re2: {}
            regex: '^cluster\.[\w]+?\.upstream_rq_[\w]+'
        - safe_regex:
            google_re2: {}
            regex: '^dns.apple.*'
        - safe_regex:
            google_re2: {}
            regex: '^http.dispatcher.*'
        - safe_regex:
            google_re2: {}
            regex: '^http.hcm.decompressor.*'
        - safe_regex:
            google_re2: {}
            regex: '^http.hcm.downstream_rq_(?:[12345]xx|total|completed)'
        - safe_regex:
            google_re2: {}
            regex: '^pulse.*'
        - safe_regex:
            google_re2: {}
            regex: '^vhost.api.vcluster\.[\w]+?\.upstream_rq_(?:[12345]xx|retry.*|time|timeout|total)'
  use_all_default_tags:
    false
watchdog:
  megamiss_timeout: 60s
  miss_timeout: 60s
node:
  metadata:
    app_id : {{ app_id }}
    app_version : {{ app_version }}
    os: {{ device_os }}
# Needed due to warning in https://github.com/envoyproxy/envoy/blob/6eb7e642d33f5a55b63c367188f09819925fca34/source/server/server.cc#L546
layered_runtime:
  layers:
    - name: static_layer_0
      static_layer:
        overload:
          global_downstream_max_connections: 50000
)";
<commit_msg>config: update keepalive settings (#1443)<commit_after>/**
 * Templated default configurations
 */

const char* platform_filter_template = R"(
          - name: envoy.filters.http.platform_bridge
            typed_config:
              "@type": type.googleapis.com/envoymobile.extensions.filters.http.platform_bridge.PlatformBridge
              platform_filter_name: {{ platform_filter_name }}
)";

const char* native_filter_template = R"(
          - name: {{ native_filter_name }}
            typed_config: {{ native_filter_typed_config }}
)";

const char* route_cache_reset_filter_template = R"(
          - name: envoy.filters.http.route_cache_reset
            typed_config:
              "@type": type.googleapis.com/envoymobile.extensions.filters.http.route_cache_reset.RouteCacheReset
)";

const char* fake_remote_listener_template = R"(
  - name: fake_remote_listener
    address:
      socket_address: { protocol: TCP, address: 127.0.0.1, port_value: 10101 }
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          stat_prefix: remote_hcm
          route_config:
            name: remote_route
            virtual_hosts:
            - name: remote_service
              domains: ["*"]
              routes:
{{ direct_responses }}
          http_filters:
          - name: envoy.router
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
)";

const char* fake_remote_cluster_template = R"(
  - name: fake_remote
    connect_timeout: 1.0s
    type: STATIC
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: fake_remote
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address: { address: 127.0.0.1, port_value: 10101 }
)";

const char* stats_sink_template = R"(
stats_sinks:
  - name: envoy.metrics_service
    typed_config:
      "@type": type.googleapis.com/envoy.config.metrics.v3.MetricsServiceConfig
      transport_api_version: V3
      report_counters_as_deltas: true
      emit_tags_as_labels: true
      grpc_service:
        envoy_grpc:
          cluster_name: stats
)";

const char* config_template = R"(
static_resources:
  listeners:
{{ fake_remote_listener }}
  - name: base_api_listener
    address:
      socket_address:
        protocol: TCP
        address: 0.0.0.0
        port_value: 10000
    per_connection_buffer_limit_bytes: 10485760 # 10MB
    api_listener:
      api_listener:
        "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
        stat_prefix: hcm
        route_config:
          name: api_router
          virtual_hosts:
            - name: api
              include_attempt_count_in_response: true
              virtual_clusters: {{ virtual_clusters }}
              domains:
                - "*"
              routes:
{{ fake_cluster_matchers }}
                - match:
                    prefix: "/"
                  route:
                    cluster_header: x-envoy-mobile-cluster
                    retry_policy:
                      retry_back_off:
                        base_interval: 0.25s
                        max_interval: 60s
        http_filters:
{{ platform_filter_chain }}
          - name: envoy.filters.http.local_error
            typed_config:
              "@type": type.googleapis.com/envoymobile.extensions.filters.http.local_error.LocalError
{{ native_filter_chain }}
          - name: envoy.filters.http.dynamic_forward_proxy
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.dynamic_forward_proxy.v3.FilterConfig
              dns_cache_config: &dns_cache_config
                name: dynamic_forward_proxy_cache_config
                # TODO: Support IPV6 https://github.com/lyft/envoy-mobile/issues/1022
                dns_lookup_family: V4_ONLY
                dns_refresh_rate: {{ dns_refresh_rate_seconds }}s
                dns_failure_refresh_rate:
                  base_interval: {{ dns_failure_refresh_rate_seconds_base }}s
                  max_interval: {{ dns_failure_refresh_rate_seconds_max }}s
          # TODO: make this configurable for users.
          - name: envoy.filters.http.decompressor
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.decompressor.v3.Decompressor
              decompressor_library:
                name: gzip
                typed_config:
                  "@type": type.googleapis.com/envoy.extensions.compression.gzip.decompressor.v3.Gzip
                  # Maximum window bits to allow for any stream to be decompressed. Optimally this
                  # would be set to 0. According to the zlib manual this would allow the decompressor
                  # to use the window bits in the zlib header to perform the decompression.
                  # Unfortunately, the proto field constraint makes this impossible currently.
                  window_bits: 15
              request_direction_config:
                common_config:
                  enabled:
                    default_value: false
                    runtime_key: request_decompressor_enabled
{{ route_reset_filter }}
          - name: envoy.router
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
  clusters:
{{ fake_remote_cluster }}
  - name: base
    connect_timeout: {{ connect_timeout_seconds }}s
    lb_policy: CLUSTER_PROVIDED
    cluster_type:
      name: envoy.clusters.dynamic_forward_proxy
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.clusters.dynamic_forward_proxy.v3.ClusterConfig
        dns_cache_config: *dns_cache_config
    transport_socket: &base_transport_socket
      name: envoy.transport_sockets.tls
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
        common_tls_context:
          validation_context:
            trusted_ca:
              inline_string: |
)"
#include "certificates.inc"

                              R"(
    upstream_connection_options: &upstream_opts
      tcp_keepalive:
        keepalive_interval: 5
        keepalive_probes: 1
        keepalive_time: 10
    circuit_breakers: &circuit_breakers_settings
      thresholds:
        - priority: DEFAULT
          # n.b: with mobile clients there are scenarios where all concurrent requests might be
          # retries (e.g., when the phone goes offline). Therefore, Envoy Mobile allows for the same
          # amount of concurrency for retries as the default value for concurrency for requests.
          # This configuration uses the default for max concurrent requests (1024) because there is
          # no reasonable scenario where a mobile client should have even close to that many concurrent
          # requests.
          #
          # `max_retries` could be used but maintainers advised against it, as there are plans to
          # deprecate that setting.
          # https://github.com/lyft/envoy-mobile/pull/811#issuecomment-619169529.
          retry_budget:
            budget_percent:
              value: 100
            min_retry_concurrency: 1024
  - name: base_wlan
    connect_timeout: {{ connect_timeout_seconds }}s
    lb_policy: CLUSTER_PROVIDED
    cluster_type:
      name: envoy.clusters.dynamic_forward_proxy
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.clusters.dynamic_forward_proxy.v3.ClusterConfig
        dns_cache_config: *dns_cache_config
    transport_socket: *base_transport_socket
    upstream_connection_options: *upstream_opts
    circuit_breakers: *circuit_breakers_settings
  - name: base_wwan
    connect_timeout: {{ connect_timeout_seconds }}s
    lb_policy: CLUSTER_PROVIDED
    cluster_type:
      name: envoy.clusters.dynamic_forward_proxy
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.clusters.dynamic_forward_proxy.v3.ClusterConfig
        dns_cache_config: *dns_cache_config
    transport_socket: *base_transport_socket
    upstream_connection_options: *upstream_opts
    circuit_breakers: *circuit_breakers_settings
  - name: base_clear
    connect_timeout: {{ connect_timeout_seconds }}s
    lb_policy: CLUSTER_PROVIDED
    cluster_type:
      name: envoy.clusters.dynamic_forward_proxy
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.clusters.dynamic_forward_proxy.v3.ClusterConfig
        dns_cache_config: *dns_cache_config
    transport_socket:
      name: envoy.transport_sockets.raw_buffer
    upstream_connection_options: *upstream_opts
    circuit_breakers: *circuit_breakers_settings
  - name: base_wlan_clear
    connect_timeout: {{ connect_timeout_seconds }}s
    lb_policy: CLUSTER_PROVIDED
    cluster_type:
      name: envoy.clusters.dynamic_forward_proxy
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.clusters.dynamic_forward_proxy.v3.ClusterConfig
        dns_cache_config: *dns_cache_config
    transport_socket:
      name: envoy.transport_sockets.raw_buffer
    upstream_connection_options: *upstream_opts
    circuit_breakers: *circuit_breakers_settings
  - name: base_wwan_clear
    connect_timeout: {{ connect_timeout_seconds }}s
    lb_policy: CLUSTER_PROVIDED
    cluster_type:
      name: envoy.clusters.dynamic_forward_proxy
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.clusters.dynamic_forward_proxy.v3.ClusterConfig
        dns_cache_config: *dns_cache_config
    transport_socket:
      name: envoy.transport_sockets.raw_buffer
    upstream_connection_options: *upstream_opts
    circuit_breakers: *circuit_breakers_settings
  - name: base_h2
    http2_protocol_options: {}
    connect_timeout: {{ connect_timeout_seconds }}s
    lb_policy: CLUSTER_PROVIDED
    cluster_type:
      name: envoy.clusters.dynamic_forward_proxy
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.clusters.dynamic_forward_proxy.v3.ClusterConfig
        dns_cache_config: *dns_cache_config
    transport_socket: *base_transport_socket
    upstream_connection_options: *upstream_opts
    circuit_breakers: *circuit_breakers_settings
  - name: base_wlan_h2
    http2_protocol_options: {}
    connect_timeout: {{ connect_timeout_seconds }}s
    lb_policy: CLUSTER_PROVIDED
    cluster_type:
      name: envoy.clusters.dynamic_forward_proxy
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.clusters.dynamic_forward_proxy.v3.ClusterConfig
        dns_cache_config: *dns_cache_config
    transport_socket: *base_transport_socket
    upstream_connection_options: *upstream_opts
    circuit_breakers: *circuit_breakers_settings
  - name: base_wwan_h2
    http2_protocol_options: {}
    connect_timeout: {{ connect_timeout_seconds }}s
    lb_policy: CLUSTER_PROVIDED
    cluster_type:
      name: envoy.clusters.dynamic_forward_proxy
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.clusters.dynamic_forward_proxy.v3.ClusterConfig
        dns_cache_config: *dns_cache_config
    transport_socket: *base_transport_socket
    upstream_connection_options: *upstream_opts
    circuit_breakers: *circuit_breakers_settings
  - name: stats
    connect_timeout: {{ connect_timeout_seconds }}s
    dns_refresh_rate: {{ dns_refresh_rate_seconds }}s
    http2_protocol_options: {}
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: stats
      endpoints:
        - lb_endpoints:
            - endpoint:
                address:
                  socket_address: {address: {{ stats_domain }}, port_value: 443}
    transport_socket: *base_transport_socket
    type: LOGICAL_DNS
stats_flush_interval: {{ stats_flush_interval_seconds }}s
{{ stats_sink }}
stats_config:
  stats_matcher:
    inclusion_list:
      patterns:
        - safe_regex:
            google_re2: {}
            regex: '^cluster\.[\w]+?\.upstream_cx_[\w]+'
        - safe_regex:
            google_re2: {}
            regex: '^cluster\.[\w]+?\.upstream_rq_[\w]+'
        - safe_regex:
            google_re2: {}
            regex: '^dns.apple.*'
        - safe_regex:
            google_re2: {}
            regex: '^http.dispatcher.*'
        - safe_regex:
            google_re2: {}
            regex: '^http.hcm.decompressor.*'
        - safe_regex:
            google_re2: {}
            regex: '^http.hcm.downstream_rq_(?:[12345]xx|total|completed)'
        - safe_regex:
            google_re2: {}
            regex: '^pulse.*'
        - safe_regex:
            google_re2: {}
            regex: '^vhost.api.vcluster\.[\w]+?\.upstream_rq_(?:[12345]xx|retry.*|time|timeout|total)'
  use_all_default_tags:
    false
watchdog:
  megamiss_timeout: 60s
  miss_timeout: 60s
node:
  metadata:
    app_id : {{ app_id }}
    app_version : {{ app_version }}
    os: {{ device_os }}
# Needed due to warning in https://github.com/envoyproxy/envoy/blob/6eb7e642d33f5a55b63c367188f09819925fca34/source/server/server.cc#L546
layered_runtime:
  layers:
    - name: static_layer_0
      static_layer:
        overload:
          global_downstream_max_connections: 50000
)";
<|endoftext|>


<commit_before>/* * This file is part of meego-keyboard *
 *
 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
 * All rights reserved.
 * Contact: Nokia Corporation (directui@nokia.com)
 *
 * If you have questions regarding the use of this file, please contact
 * Nokia at directui@nokia.com.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation
 * and appearing in the file LICENSE.LGPL included in the packaging
 * of this file.
 */

#include "mvirtualkeyboardstyle.h"
#include "horizontalswitcher.h"
#include "layoutsmanager.h"
#include "symbolview.h"
#include "grip.h"
#include "mimkeyarea.h"
#include "regiontracker.h"

#include <MSceneManager>
#include <MScalableImage>
#include <mreactionmap.h>
#include <mplainwindow.h>

#include <QDebug>
#include <QGraphicsSceneResizeEvent>
#include <QGraphicsLinearLayout>

namespace
{
    const QString SymbolSectionPrefix = "symbols";
    const QString SymbolSectionSym = SymbolSectionPrefix + "0";

    // This GConf item defines whether multitouch is enabled or disabled
    const char * const MultitouchSettings = "/meegotouch/inputmethods/multitouch/enabled";
};

SymbolView::SymbolView(const LayoutsManager &layoutsManager, const MVirtualKeyboardStyleContainer *style,
                       const QString &layout, QGraphicsWidget *parent)
    : MWidget(parent),
      styleContainer(style),
      sceneManager(*MPlainWindow::instance()->sceneManager()),
      activity(Inactive),
      activePage(0),
      shiftState(ModifierClearState),
      layoutsMgr(layoutsManager),
      pageSwitcher(0),
      currentOrientation(sceneManager.orientation()),
      currentLayout(layout),
      mouseDownKeyArea(false),
      mainLayout(new QGraphicsLinearLayout(Qt::Vertical, this)),
      activeState(MInputMethod::OnScreen)
{
    setObjectName("SymbolView");
    RegionTracker::instance().addRegion(*this);
    RegionTracker::instance().addInputMethodArea(*this);

    connect(&eventHandler, SIGNAL(keyPressed(KeyEvent)),
            this,          SIGNAL(keyPressed(KeyEvent)));
    connect(&eventHandler, SIGNAL(keyReleased(KeyEvent)),
            this,          SIGNAL(keyReleased(KeyEvent)));
    connect(&eventHandler, SIGNAL(keyClicked(KeyEvent)),
            this,          SIGNAL(keyClicked(KeyEvent)));
    connect(&eventHandler, SIGNAL(longKeyPressed(const KeyEvent &)),
            this,          SIGNAL(longKeyPressed(const KeyEvent &)));
    connect(&eventHandler, SIGNAL(shiftPressed(bool)),
            this,          SLOT(handleShiftPressed(bool)));

    connect(&layoutsManager, SIGNAL(hardwareLayoutChanged()),
            this, SLOT(handleHwLayoutChange()));

    enableMultiTouch = MGConfItem(MultitouchSettings).value().toBool();

    hide();
    setupLayout();
    reloadContent();
}

SymbolView::~SymbolView()
{}

void SymbolView::setupLayout()
{
    // Layout widths are set in organizeContent().

    setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Maximum);

    mainLayout->setSpacing(0);
    mainLayout->setContentsMargins(0, 0, 0, 0);

    Grip *symbolViewGrip = new Grip(this);
    symbolViewGrip->setObjectName("KeyboardHandle");
    mainLayout->insertItem(GripIndex, symbolViewGrip);

    // Urghs, we have a non-virtual override for setLayout ...
    QGraphicsWidget::setLayout(mainLayout);

    connectHandle(symbolViewGrip);
}

void SymbolView::connectHandle(Handle *handle)
{
    connect(handle, SIGNAL(flickLeft(FlickGesture)),
            this,   SLOT(switchToNextPage()),
            Qt::UniqueConnection);

    connect(handle, SIGNAL(flickRight(FlickGesture)),
            this,   SLOT(switchToPrevPage()),
            Qt::UniqueConnection);

    connect(handle, SIGNAL(flickDown(FlickGesture)),
            this,   SLOT(hideSymbolView()),
            Qt::UniqueConnection);
}

void SymbolView::reloadContent()
{
    if (activeState == MInputMethod::OnScreen) {
        // Get layout model which for current layout and orientation.
        const LayoutData *layoutData = layoutsMgr.layout(currentLayout, LayoutData::General, currentOrientation);

        loadSwitcherPages(layoutData, activePage);
        setShiftState(shiftState);
    } else if (activeState == MInputMethod::Hardware && currentOrientation == M::Landscape) {
        const LayoutData *layoutData = layoutsMgr.hardwareLayout(LayoutData::General, M::Landscape);
        if (!layoutData) {
            // Get it by layout then.
            layoutData = layoutsMgr.layout(currentLayout, LayoutData::General, M::Landscape);
        }

        loadSwitcherPages(layoutData, activePage);
        setShiftState(shiftState); // Sets level for sym pages.
    }
    layout()->invalidate();
}

void SymbolView::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
{
    const MScalableImage *background = style()->backgroundImage();

    if (background) {
        // Background covers everything except top layout.
        background->draw(mainLayout->itemAt(KeyboardIndex)->geometry().toRect(), painter);
    }
}

QVariant SymbolView::itemChange(GraphicsItemChange change, const QVariant &value)
{
    if (change == QGraphicsItem::ItemSceneHasChanged) {
        QGraphicsScene *newScene = value.value<QGraphicsScene *>();
        if (newScene != 0 && pageSwitcher) {
            // Usually this happens only once when symbolView is first put into a scene.

            // Reinstall scene event filter.
            for (int i = 0; i < pageSwitcher->count(); ++i) {
                pageSwitcher->widget(i)->removeSceneEventFilter(this);
                pageSwitcher->widget(i)->installSceneEventFilter(this);
            }
        }
    } else if (change == QGraphicsItem::ItemVisibleChange && value.toBool()) {
        organizeContent();
    }
    return QGraphicsItem::itemChange(change, value);
}

void SymbolView::mousePressEvent(QGraphicsSceneMouseEvent *)
{
    // Nothing, just stop the event from propagating
}

bool SymbolView::sceneEventFilter(QGraphicsItem */*watched*/, QEvent *event)
{
    if (pageSwitcher) {
        switch (event->type()) {
        case QEvent::GraphicsSceneMousePress: {
            mouseDownKeyArea = true;
        } break;
        case QEvent::GraphicsSceneMouseRelease: {
            // Even though at this point ungrabbing the child widget would allow release
            // event to reach it the order is wrong. We now cope with the situation because
            // we know MImAbstractKeyAreas will ungrab even an implicit grab on release event.
            mouseDownKeyArea = false;

            // Hide SymbolView if temporary mode was on.
            if (activity == TemporarilyActive) {
                hideSymbolView();
            }
        } break;
        default:
            break;
        }
    }
    return false;
}

void SymbolView::prepareToOrientationChange()
{
    qDebug() << __PRETTY_FUNCTION__;

    // if inactive, just ignore
    if (!isActive()) {
        return;
    }
    activity = TemporarilyInactive;
}

void SymbolView::finalizeOrientationChange()
{
    organizeContent();
    if (activity == TemporarilyInactive) {
        //reshow the page
        showSymbolView(NormalShowMode);
    }
}

void SymbolView::showSymbolView(SymbolView::ShowMode mode)
{
    if (mode == FollowMouseShowMode) {
        activity = TemporarilyActive;
    } else {
        activity = Active;
    }
    show();
}

void SymbolView::hideSymbolView(SymbolView::HideMode mode)
{
    hide();
    if (activity == TemporarilyInactive && mode == NormalHideMode) {
        activity = Inactive;
        return;
    }

    if (!isActive()) {
        return;
    }

    if (mode == NormalHideMode) {
        pageSwitcher->setCurrent(0);
    }

    if (mode == TemporaryHideMode) {
        activity = TemporarilyInactive;
    } else {
        activity = Inactive;
    }
}

void SymbolView::loadSwitcherPages(const LayoutData *kbLayout, const unsigned int selectPage)
{
    layout()->invalidate();

    if (pageSwitcher) {
        mainLayout->removeItem(pageSwitcher);
        delete pageSwitcher;
        pageSwitcher = 0;
    }

    if (!kbLayout) {
        return;
    }

    pageSwitcher = new HorizontalSwitcher(this);
    pageSwitcher->setLooping(true);
    pageSwitcher->setAnimationEnabled(false);

    connect(pageSwitcher, SIGNAL(switchStarting(QGraphicsWidget *, QGraphicsWidget *)),
            this,         SLOT(onSwitchStarting(QGraphicsWidget *, QGraphicsWidget *)));
    connect(pageSwitcher, SIGNAL(switchDone(QGraphicsWidget *, QGraphicsWidget *)),
            this,         SLOT(onSwitchDone()));

    LayoutData::SharedLayoutSection symbolSection;

    // Add special Sym section always as the first, if present.
    symbolSection = kbLayout->section(SymbolSectionSym);
    if (!symbolSection.isNull()) {
        addPage(symbolSection);
    }

    // Add all others.
    for (int i = 0; i < kbLayout->numSections(); ++i) {
        symbolSection = kbLayout->section(i);

        // Skip those that are not symbol sections.
        if (symbolSection->name().startsWith(SymbolSectionPrefix) &&
                // Skip also sym section because we added it already.
                (symbolSection->name() != SymbolSectionSym)) {
            addPage(symbolSection);
        }
    }

    if (pageSwitcher->count() >= 0) {
        activePage = (selectPage >= static_cast<unsigned int>(pageSwitcher->count()) ? 0 : selectPage);
        pageSwitcher->setCurrent(activePage);
    }

    pageSwitcher->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
    mainLayout->insertItem(KeyboardIndex, pageSwitcher);
}

void SymbolView::addPage(const LayoutData::SharedLayoutSection &symbolSection)
{
    MImAbstractKeyArea *page = createMImAbstractKeyArea(symbolSection);

    if (page) {
        page->setObjectName("SymbolMainRow");

        connect(this, SIGNAL(levelSwitched(int)), page, SLOT(switchLevel(int)));

        connect(page, SIGNAL(flickLeft()), SLOT(switchToNextPage()));
        connect(page, SIGNAL(flickRight()), SLOT(switchToPrevPage()));
        connect(page, SIGNAL(flickDown()), SLOT(hideSymbolView()));

        pageSwitcher->addWidget(page);

        // Track children's mouse events.
        // If we don't yet have a scene, the filter won't be installed. Then we do this
        // later in SymbolView::itemChange().
        if (scene()) {
            page->installSceneEventFilter(this);
        }
    }
}

MImAbstractKeyArea *SymbolView::createMImAbstractKeyArea(const LayoutData::SharedLayoutSection &section,
                                               bool enablePopup)
{
    MImAbstractKeyArea *keysWidget = 0;

    if (!section.isNull()) {
        keysWidget = new MImKeyArea(section, enablePopup);

        eventHandler.addEventSource(keysWidget);
    }

    return keysWidget;
}

void SymbolView::organizeContent()
{
    const M::Orientation orientation(sceneManager.orientation());
    const int sceneWidth = sceneManager.visibleSceneSize().width();

    setPreferredWidth(sceneWidth);
    setMaximumWidth(sceneWidth);
    setMinimumWidth(sceneWidth);

    if (currentOrientation != orientation) {
        currentOrientation = orientation;
        reloadContent();
    }
}

void SymbolView::setShiftState(ModifierState newShiftState)
{
    const int level = newShiftState != ModifierClearState ? 1 : 0;
    shiftState = newShiftState;

    for (int i = 0; i < pageSwitcher->count(); ++i) {
        MImAbstractKeyArea *mainKba = static_cast<MImAbstractKeyArea *>(pageSwitcher->widget(i));
        if (mainKba) {
            mainKba->setShiftState(shiftState);
        }
    }

    emit levelSwitched(level);
}

int SymbolView::currentLevel() const
{
    return (shiftState != ModifierClearState);
}

void SymbolView::handleHwLayoutChange()
{
    if (activeState == MInputMethod::Hardware) {
        reloadContent();
    }
}

void SymbolView::setKeyboardState(MInputMethod::HandlerState newState)
{
    if (activeState != newState) {
        activeState = newState;
        reloadContent();
    }
}

void SymbolView::setLayout(const QString &layoutFile)
{
    if (layoutFile != currentLayout && layoutsMgr.layoutFileList().contains(layoutFile)) {
        currentLayout = layoutFile;

    // Only on-screen sym follows layout.
        if (activeState == MInputMethod::OnScreen) {
            reloadContent();
        }
    }
}

void SymbolView::switchToNextPage()
{
    pageSwitcher->switchTo((pageCount() == 2 && pageSwitcher->current() == 1)
                           ? HorizontalSwitcher::Left : HorizontalSwitcher::Right);
}

void SymbolView::switchToPrevPage()
{
    pageSwitcher->switchTo((pageCount() == 2 && pageSwitcher->current() == 0)
                           ? HorizontalSwitcher::Right : HorizontalSwitcher::Left);
}

void SymbolView::onSwitchStarting(QGraphicsWidget *current, QGraphicsWidget *next)
{
    if (mouseDownKeyArea) {
        if (current) {
            // This is required because, for some reason, Qt
            // does not allow mouse grab for item that was hidden
            // when it had the grab. Even though hiding an item
            // should release the grab. So this call does not affect
            // the following grabMouse() but it affects the behaviour
            // if we get back to this page during the same mouse move.
            current->ungrabMouse();
        }
        next->grabMouse();
    }
}

void SymbolView::onSwitchDone()
{
    // Don't reset reactive areas if, for some reason, switch is finished
    // after we've been hidden.
    if (isVisible()) {
        layout()->activate();
        emit RegionTracker::instance().requestReactionMapUpdate();
    }
    if (pageSwitcher) {
        activePage = pageSwitcher->current();
    }
}

void SymbolView::handleShiftPressed(bool shiftPressed)
{
    if (enableMultiTouch) {
        const int level = shiftPressed ? 1 : currentLevel();

        MImAbstractKeyArea *mainKba = static_cast<MImAbstractKeyArea *>(pageSwitcher->currentWidget());
        if (mainKba) {
            mainKba->switchLevel(level);
        }
    }
}

void SymbolView::paintReactionMap(MReactionMap *reactionMap, QGraphicsView *view)
{
    // Draw region area with inactive color to prevent any holes in reaction map.
    reactionMap->setInactiveDrawingValue();
    reactionMap->setTransform(this, view);
    foreach(const QRect & rect, interactiveRegion().rects()) {
        reactionMap->fillRectangle(mapRectFromScene(rect));
    }

    reactionMap->setReactiveDrawingValue();

    // Draw current character view.
    if (pageSwitcher->currentWidget()) {
        static_cast<MImAbstractKeyArea *>(pageSwitcher->currentWidget())->drawReactiveAreas(reactionMap, view);
    }
}

const MVirtualKeyboardStyleContainer &SymbolView::style() const
{
    return *styleContainer;
}

bool SymbolView::isActive() const
{
    return ((activity == Active) || (activity == TemporarilyActive));
}

QString SymbolView::pageTitle(const int pageIndex) const
{
    Q_ASSERT(pageSwitcher && (pageSwitcher->count() > pageIndex));
    const QString sectionName = qobject_cast<const MImAbstractKeyArea *>(pageSwitcher->widget(pageIndex))->sectionModel()->name();
    return sectionName.mid(SymbolSectionPrefix.length());
}

QRegion SymbolView::interactiveRegion() const
{
    QRegion region;

    // SymbolView always occupies the same area if opened.
    if (isActive()) {
        region |= mapRectToScene(mainLayout->geometry()).toRect();
    }

    return region;
}

int SymbolView::pageCount() const
{
    return pageSwitcher->count();
}

int SymbolView::currentPage() const
{
    return activePage;
}

void SymbolView::setTemporarilyHidden(bool hidden)
{
    if (hidden && activity == Active) {
        hideSymbolView(TemporaryHideMode);
    } else if (!hidden && activity == TemporarilyInactive) {
        showSymbolView();
    }
}

<commit_msg>Changes: Remove incorrect emit keyword.<commit_after>/* * This file is part of meego-keyboard *
 *
 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
 * All rights reserved.
 * Contact: Nokia Corporation (directui@nokia.com)
 *
 * If you have questions regarding the use of this file, please contact
 * Nokia at directui@nokia.com.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation
 * and appearing in the file LICENSE.LGPL included in the packaging
 * of this file.
 */

#include "mvirtualkeyboardstyle.h"
#include "horizontalswitcher.h"
#include "layoutsmanager.h"
#include "symbolview.h"
#include "grip.h"
#include "mimkeyarea.h"
#include "regiontracker.h"

#include <MSceneManager>
#include <MScalableImage>
#include <mreactionmap.h>
#include <mplainwindow.h>

#include <QDebug>
#include <QGraphicsSceneResizeEvent>
#include <QGraphicsLinearLayout>

namespace
{
    const QString SymbolSectionPrefix = "symbols";
    const QString SymbolSectionSym = SymbolSectionPrefix + "0";

    // This GConf item defines whether multitouch is enabled or disabled
    const char * const MultitouchSettings = "/meegotouch/inputmethods/multitouch/enabled";
};

SymbolView::SymbolView(const LayoutsManager &layoutsManager, const MVirtualKeyboardStyleContainer *style,
                       const QString &layout, QGraphicsWidget *parent)
    : MWidget(parent),
      styleContainer(style),
      sceneManager(*MPlainWindow::instance()->sceneManager()),
      activity(Inactive),
      activePage(0),
      shiftState(ModifierClearState),
      layoutsMgr(layoutsManager),
      pageSwitcher(0),
      currentOrientation(sceneManager.orientation()),
      currentLayout(layout),
      mouseDownKeyArea(false),
      mainLayout(new QGraphicsLinearLayout(Qt::Vertical, this)),
      activeState(MInputMethod::OnScreen)
{
    setObjectName("SymbolView");
    RegionTracker::instance().addRegion(*this);
    RegionTracker::instance().addInputMethodArea(*this);

    connect(&eventHandler, SIGNAL(keyPressed(KeyEvent)),
            this,          SIGNAL(keyPressed(KeyEvent)));
    connect(&eventHandler, SIGNAL(keyReleased(KeyEvent)),
            this,          SIGNAL(keyReleased(KeyEvent)));
    connect(&eventHandler, SIGNAL(keyClicked(KeyEvent)),
            this,          SIGNAL(keyClicked(KeyEvent)));
    connect(&eventHandler, SIGNAL(longKeyPressed(const KeyEvent &)),
            this,          SIGNAL(longKeyPressed(const KeyEvent &)));
    connect(&eventHandler, SIGNAL(shiftPressed(bool)),
            this,          SLOT(handleShiftPressed(bool)));

    connect(&layoutsManager, SIGNAL(hardwareLayoutChanged()),
            this, SLOT(handleHwLayoutChange()));

    enableMultiTouch = MGConfItem(MultitouchSettings).value().toBool();

    hide();
    setupLayout();
    reloadContent();
}

SymbolView::~SymbolView()
{}

void SymbolView::setupLayout()
{
    // Layout widths are set in organizeContent().

    setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Maximum);

    mainLayout->setSpacing(0);
    mainLayout->setContentsMargins(0, 0, 0, 0);

    Grip *symbolViewGrip = new Grip(this);
    symbolViewGrip->setObjectName("KeyboardHandle");
    mainLayout->insertItem(GripIndex, symbolViewGrip);

    // Urghs, we have a non-virtual override for setLayout ...
    QGraphicsWidget::setLayout(mainLayout);

    connectHandle(symbolViewGrip);
}

void SymbolView::connectHandle(Handle *handle)
{
    connect(handle, SIGNAL(flickLeft(FlickGesture)),
            this,   SLOT(switchToNextPage()),
            Qt::UniqueConnection);

    connect(handle, SIGNAL(flickRight(FlickGesture)),
            this,   SLOT(switchToPrevPage()),
            Qt::UniqueConnection);

    connect(handle, SIGNAL(flickDown(FlickGesture)),
            this,   SLOT(hideSymbolView()),
            Qt::UniqueConnection);
}

void SymbolView::reloadContent()
{
    if (activeState == MInputMethod::OnScreen) {
        // Get layout model which for current layout and orientation.
        const LayoutData *layoutData = layoutsMgr.layout(currentLayout, LayoutData::General, currentOrientation);

        loadSwitcherPages(layoutData, activePage);
        setShiftState(shiftState);
    } else if (activeState == MInputMethod::Hardware && currentOrientation == M::Landscape) {
        const LayoutData *layoutData = layoutsMgr.hardwareLayout(LayoutData::General, M::Landscape);
        if (!layoutData) {
            // Get it by layout then.
            layoutData = layoutsMgr.layout(currentLayout, LayoutData::General, M::Landscape);
        }

        loadSwitcherPages(layoutData, activePage);
        setShiftState(shiftState); // Sets level for sym pages.
    }
    layout()->invalidate();
}

void SymbolView::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
{
    const MScalableImage *background = style()->backgroundImage();

    if (background) {
        // Background covers everything except top layout.
        background->draw(mainLayout->itemAt(KeyboardIndex)->geometry().toRect(), painter);
    }
}

QVariant SymbolView::itemChange(GraphicsItemChange change, const QVariant &value)
{
    if (change == QGraphicsItem::ItemSceneHasChanged) {
        QGraphicsScene *newScene = value.value<QGraphicsScene *>();
        if (newScene != 0 && pageSwitcher) {
            // Usually this happens only once when symbolView is first put into a scene.

            // Reinstall scene event filter.
            for (int i = 0; i < pageSwitcher->count(); ++i) {
                pageSwitcher->widget(i)->removeSceneEventFilter(this);
                pageSwitcher->widget(i)->installSceneEventFilter(this);
            }
        }
    } else if (change == QGraphicsItem::ItemVisibleChange && value.toBool()) {
        organizeContent();
    }
    return QGraphicsItem::itemChange(change, value);
}

void SymbolView::mousePressEvent(QGraphicsSceneMouseEvent *)
{
    // Nothing, just stop the event from propagating
}

bool SymbolView::sceneEventFilter(QGraphicsItem */*watched*/, QEvent *event)
{
    if (pageSwitcher) {
        switch (event->type()) {
        case QEvent::GraphicsSceneMousePress: {
            mouseDownKeyArea = true;
        } break;
        case QEvent::GraphicsSceneMouseRelease: {
            // Even though at this point ungrabbing the child widget would allow release
            // event to reach it the order is wrong. We now cope with the situation because
            // we know MImAbstractKeyAreas will ungrab even an implicit grab on release event.
            mouseDownKeyArea = false;

            // Hide SymbolView if temporary mode was on.
            if (activity == TemporarilyActive) {
                hideSymbolView();
            }
        } break;
        default:
            break;
        }
    }
    return false;
}

void SymbolView::prepareToOrientationChange()
{
    qDebug() << __PRETTY_FUNCTION__;

    // if inactive, just ignore
    if (!isActive()) {
        return;
    }
    activity = TemporarilyInactive;
}

void SymbolView::finalizeOrientationChange()
{
    organizeContent();
    if (activity == TemporarilyInactive) {
        //reshow the page
        showSymbolView(NormalShowMode);
    }
}

void SymbolView::showSymbolView(SymbolView::ShowMode mode)
{
    if (mode == FollowMouseShowMode) {
        activity = TemporarilyActive;
    } else {
        activity = Active;
    }
    show();
}

void SymbolView::hideSymbolView(SymbolView::HideMode mode)
{
    hide();
    if (activity == TemporarilyInactive && mode == NormalHideMode) {
        activity = Inactive;
        return;
    }

    if (!isActive()) {
        return;
    }

    if (mode == NormalHideMode) {
        pageSwitcher->setCurrent(0);
    }

    if (mode == TemporaryHideMode) {
        activity = TemporarilyInactive;
    } else {
        activity = Inactive;
    }
}

void SymbolView::loadSwitcherPages(const LayoutData *kbLayout, const unsigned int selectPage)
{
    layout()->invalidate();

    if (pageSwitcher) {
        mainLayout->removeItem(pageSwitcher);
        delete pageSwitcher;
        pageSwitcher = 0;
    }

    if (!kbLayout) {
        return;
    }

    pageSwitcher = new HorizontalSwitcher(this);
    pageSwitcher->setLooping(true);
    pageSwitcher->setAnimationEnabled(false);

    connect(pageSwitcher, SIGNAL(switchStarting(QGraphicsWidget *, QGraphicsWidget *)),
            this,         SLOT(onSwitchStarting(QGraphicsWidget *, QGraphicsWidget *)));
    connect(pageSwitcher, SIGNAL(switchDone(QGraphicsWidget *, QGraphicsWidget *)),
            this,         SLOT(onSwitchDone()));

    LayoutData::SharedLayoutSection symbolSection;

    // Add special Sym section always as the first, if present.
    symbolSection = kbLayout->section(SymbolSectionSym);
    if (!symbolSection.isNull()) {
        addPage(symbolSection);
    }

    // Add all others.
    for (int i = 0; i < kbLayout->numSections(); ++i) {
        symbolSection = kbLayout->section(i);

        // Skip those that are not symbol sections.
        if (symbolSection->name().startsWith(SymbolSectionPrefix) &&
                // Skip also sym section because we added it already.
                (symbolSection->name() != SymbolSectionSym)) {
            addPage(symbolSection);
        }
    }

    if (pageSwitcher->count() >= 0) {
        activePage = (selectPage >= static_cast<unsigned int>(pageSwitcher->count()) ? 0 : selectPage);
        pageSwitcher->setCurrent(activePage);
    }

    pageSwitcher->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
    mainLayout->insertItem(KeyboardIndex, pageSwitcher);
}

void SymbolView::addPage(const LayoutData::SharedLayoutSection &symbolSection)
{
    MImAbstractKeyArea *page = createMImAbstractKeyArea(symbolSection);

    if (page) {
        page->setObjectName("SymbolMainRow");

        connect(this, SIGNAL(levelSwitched(int)), page, SLOT(switchLevel(int)));

        connect(page, SIGNAL(flickLeft()), SLOT(switchToNextPage()));
        connect(page, SIGNAL(flickRight()), SLOT(switchToPrevPage()));
        connect(page, SIGNAL(flickDown()), SLOT(hideSymbolView()));

        pageSwitcher->addWidget(page);

        // Track children's mouse events.
        // If we don't yet have a scene, the filter won't be installed. Then we do this
        // later in SymbolView::itemChange().
        if (scene()) {
            page->installSceneEventFilter(this);
        }
    }
}

MImAbstractKeyArea *SymbolView::createMImAbstractKeyArea(const LayoutData::SharedLayoutSection &section,
                                               bool enablePopup)
{
    MImAbstractKeyArea *keysWidget = 0;

    if (!section.isNull()) {
        keysWidget = new MImKeyArea(section, enablePopup);

        eventHandler.addEventSource(keysWidget);
    }

    return keysWidget;
}

void SymbolView::organizeContent()
{
    const M::Orientation orientation(sceneManager.orientation());
    const int sceneWidth = sceneManager.visibleSceneSize().width();

    setPreferredWidth(sceneWidth);
    setMaximumWidth(sceneWidth);
    setMinimumWidth(sceneWidth);

    if (currentOrientation != orientation) {
        currentOrientation = orientation;
        reloadContent();
    }
}

void SymbolView::setShiftState(ModifierState newShiftState)
{
    const int level = newShiftState != ModifierClearState ? 1 : 0;
    shiftState = newShiftState;

    for (int i = 0; i < pageSwitcher->count(); ++i) {
        MImAbstractKeyArea *mainKba = static_cast<MImAbstractKeyArea *>(pageSwitcher->widget(i));
        if (mainKba) {
            mainKba->setShiftState(shiftState);
        }
    }

    emit levelSwitched(level);
}

int SymbolView::currentLevel() const
{
    return (shiftState != ModifierClearState);
}

void SymbolView::handleHwLayoutChange()
{
    if (activeState == MInputMethod::Hardware) {
        reloadContent();
    }
}

void SymbolView::setKeyboardState(MInputMethod::HandlerState newState)
{
    if (activeState != newState) {
        activeState = newState;
        reloadContent();
    }
}

void SymbolView::setLayout(const QString &layoutFile)
{
    if (layoutFile != currentLayout && layoutsMgr.layoutFileList().contains(layoutFile)) {
        currentLayout = layoutFile;

    // Only on-screen sym follows layout.
        if (activeState == MInputMethod::OnScreen) {
            reloadContent();
        }
    }
}

void SymbolView::switchToNextPage()
{
    pageSwitcher->switchTo((pageCount() == 2 && pageSwitcher->current() == 1)
                           ? HorizontalSwitcher::Left : HorizontalSwitcher::Right);
}

void SymbolView::switchToPrevPage()
{
    pageSwitcher->switchTo((pageCount() == 2 && pageSwitcher->current() == 0)
                           ? HorizontalSwitcher::Right : HorizontalSwitcher::Left);
}

void SymbolView::onSwitchStarting(QGraphicsWidget *current, QGraphicsWidget *next)
{
    if (mouseDownKeyArea) {
        if (current) {
            // This is required because, for some reason, Qt
            // does not allow mouse grab for item that was hidden
            // when it had the grab. Even though hiding an item
            // should release the grab. So this call does not affect
            // the following grabMouse() but it affects the behaviour
            // if we get back to this page during the same mouse move.
            current->ungrabMouse();
        }
        next->grabMouse();
    }
}

void SymbolView::onSwitchDone()
{
    // Don't reset reactive areas if, for some reason, switch is finished
    // after we've been hidden.
    if (isVisible()) {
        layout()->activate();
        RegionTracker::instance().requestReactionMapUpdate();
    }
    if (pageSwitcher) {
        activePage = pageSwitcher->current();
    }
}

void SymbolView::handleShiftPressed(bool shiftPressed)
{
    if (enableMultiTouch) {
        const int level = shiftPressed ? 1 : currentLevel();

        MImAbstractKeyArea *mainKba = static_cast<MImAbstractKeyArea *>(pageSwitcher->currentWidget());
        if (mainKba) {
            mainKba->switchLevel(level);
        }
    }
}

void SymbolView::paintReactionMap(MReactionMap *reactionMap, QGraphicsView *view)
{
    // Draw region area with inactive color to prevent any holes in reaction map.
    reactionMap->setInactiveDrawingValue();
    reactionMap->setTransform(this, view);
    foreach(const QRect & rect, interactiveRegion().rects()) {
        reactionMap->fillRectangle(mapRectFromScene(rect));
    }

    reactionMap->setReactiveDrawingValue();

    // Draw current character view.
    if (pageSwitcher->currentWidget()) {
        static_cast<MImAbstractKeyArea *>(pageSwitcher->currentWidget())->drawReactiveAreas(reactionMap, view);
    }
}

const MVirtualKeyboardStyleContainer &SymbolView::style() const
{
    return *styleContainer;
}

bool SymbolView::isActive() const
{
    return ((activity == Active) || (activity == TemporarilyActive));
}

QString SymbolView::pageTitle(const int pageIndex) const
{
    Q_ASSERT(pageSwitcher && (pageSwitcher->count() > pageIndex));
    const QString sectionName = qobject_cast<const MImAbstractKeyArea *>(pageSwitcher->widget(pageIndex))->sectionModel()->name();
    return sectionName.mid(SymbolSectionPrefix.length());
}

QRegion SymbolView::interactiveRegion() const
{
    QRegion region;

    // SymbolView always occupies the same area if opened.
    if (isActive()) {
        region |= mapRectToScene(mainLayout->geometry()).toRect();
    }

    return region;
}

int SymbolView::pageCount() const
{
    return pageSwitcher->count();
}

int SymbolView::currentPage() const
{
    return activePage;
}

void SymbolView::setTemporarilyHidden(bool hidden)
{
    if (hidden && activity == Active) {
        hideSymbolView(TemporaryHideMode);
    } else if (!hidden && activity == TemporarilyInactive) {
        showSymbolView();
    }
}

<|endoftext|>


<commit_before>#include "SysConfig.h"
#if(HAS_PCA9539)

#include <CI2C.h>
#include "CPCA9539.h"
#include "CTimer.h"
#include "NDataManager.h"

namespace
{
    CTimer pca9539_sample_timer;
}

CPCA9539::CPCA9539( CI2C *i2cInterfaceIn )
    : m_pca( i2cInterfaceIn )
{

}

void CPCA9539::Initialize()
{
    Serial.println( "CPCA9539.Status:INIT;" );

    pca9539_sample_timer.Reset();

    Serial.println( "CPCA9539.Status:POST_INIT;");
}

void CPCA9539::Update( CCommand &commandIn )
{
    if( pca9539_sample_timer.HasElapsed( 1000 ) )
    {
        Serial.println( "PCA9539.Status:LOOP;" );
        m_pca.Initialize();
    }
}

#endif<commit_msg>class usage test<commit_after>#include "SysConfig.h"
#if(HAS_PCA9539)

#include <CI2C.h>
#include "CPCA9539.h"
#include "CTimer.h"
#include "NDataManager.h"

namespace
{
    CTimer pca9539_sample_timer;
    bool toggle = true;

}

CPCA9539::CPCA9539( CI2C *i2cInterfaceIn )
    : m_pca( i2cInterfaceIn )
{

}

void CPCA9539::Initialize()
{
    Serial.println( "CPCA9539.Status:INIT;" );

    pca9539_sample_timer.Reset();
    m_pca.Initialize();
    m_pca.PinMode( OUTPUT );

    Serial.println( "CPCA9539.Status:POST_INIT;");
}

void CPCA9539::Update( CCommand &commandIn )
{
    if( pca9539_sample_timer.HasElapsed( 1000 ) )
    {
        Serial.println( "PCA9539.Status:LOOP;" );
        if( toggle )
        {
            auto ret = m_pca.DigitalWrite( 0 , HIGH )
            Serial.println( ret );
        }
        else
        {
            auto ret = m_pca.DigitalWrite( 0 , LOW )
            Serial.println( ret );
        }

    }
}

#endif<|endoftext|>