<commit_before>/* mbed Microcontroller Library
 * Copyright (c) 2006-2015 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "mbed.h"
#include "ble/BLE.h"
#include "ble-blocktransfer/BlockTransferService.h"
#include "voytalk/VoytalkHub.h"

/*****************************************************************************/
/* Configuration                                                             */
/*****************************************************************************/

// set device name
const char DEVICE_NAME[] = "Nesvoy";

// set TX power
#ifndef CFG_BLE_TX_POWER_LEVEL
#define CFG_BLE_TX_POWER_LEVEL 0
#endif

// control debug output
#if 1
#define DEBUGOUT(...) { printf(__VA_ARGS__); }
#else
#define DEBUGOUT(...) /* nothing */
#endif // DEBUGOUT

/*****************************************************************************/

/* Voytalk short UUID */
const UUID uuid(0xFE8E);

/* Voytalk states */
typedef enum {
    FLAG_CONNECTED      = 0x01,
    FLAG_PROVISIONED    = 0x02,
} flags_t;

static volatile uint8_t state;

/*****************************************************************************/
/* Global variables used by the test app                                     */
/*****************************************************************************/

// BLE_API ble device
BLE ble;

// Transfer large blocks of data on platforms without Fragmentation-And-Recombination
BlockTransferService bts;

// Voytalk handling
VoytalkHub vthub(DEVICE_NAME);

// buffer for sending and receiving data
SharedPointer<Block> writeBlock;
uint8_t readBuffer[1000];
BlockStatic readBlock(readBuffer, sizeof(readBuffer));

// wifi parameters
std::string ssid_string;
std::string key_string;

// Compatibility function
void signalReady();

/*****************************************************************************/
/* Functions for handling debug output                                       */
/*****************************************************************************/

/*
    Functions called when BLE device connects and disconnects.
*/
void whenConnected(const Gap::ConnectionCallbackParams_t* params)
{
    (void) params;
    DEBUGOUT("main: Connected: %d %d %d\r\n", params->connectionParams->minConnectionInterval,
                                              params->connectionParams->maxConnectionInterval,
                                              params->connectionParams->slaveLatency);

    // change state in main application
    state |= FLAG_CONNECTED;

    // change state inside Voytalk hub
    vthub.setStateMask(state);
}

void whenDisconnected(const Gap::DisconnectionCallbackParams_t*)
{
    DEBUGOUT("main: Disconnected!\r\n");
    DEBUGOUT("main: Restarting the advertising process\r\n");

    ble.gap().startAdvertising();

    // change state in main application
    state &= ~FLAG_CONNECTED;

    // change state inside Voytalk hub
    vthub.setStateMask(state);
}

/*****************************************************************************/
/* BlockTransfer callbacks for sending and receiving data                    */
/*****************************************************************************/

/*
    Function called when signaling client that new data is ready to be read.
*/
void blockServerSendNotification()
{
    DEBUGOUT("main: notify read updated\r\n");
    bts.updateCharacteristicValue((uint8_t*)"", 0);
}

/*
    Function called when device receives a read request over BLE.
*/
SharedPointer<Block> blockServerReadHandler(uint32_t offset)
{
    DEBUGOUT("main: block read\r\n");
    (void) offset;

    return SharedPointer<Block>(new BlockStatic(readBlock));
}

/*
    Function called when data has been written over BLE.
*/
void blockServerWriteHandler(SharedPointer<Block> block)
{
    DEBUGOUT("main: block write\r\n");

    /*
        Process received data, assuming it is CBOR encoded.
        Any output generated will be written to the readBlock.
    */
    vthub.processCBOR((BlockStatic*) block.get(), &readBlock);

    /*
        If the readBlock length is non-zero it means a reply has been generated.
    */
    if (readBlock.getLength() > 0)
    {
        signalReady();
    }
}

/*****************************************************************************/
/* Voytalk Wifi example                                                      */
/*****************************************************************************/

/*
    Callback function for constructing wifi intent.
*/
void wifiIntentConstruction(VoytalkHub& hub)
{
    DEBUGOUT("main: wifi intent construction\r\n");
    /* create intent using generated endpoint and constraint set */
    VoytalkIntent intent("com.arm.connectivity.wifi");

    /* serialize object tree to CBOR */
    hub.processIntent(intent);
}

void wifiIntentInvocation(VoytalkHub& hub, VoytalkIntentInvocation& object)
{
    DEBUGOUT("main: wifi invocation\r\n");

    // debug: print object tree
    object.print();

    /////////////////////////////////////////
    // retrieve parameters
    ssid_string = object.getParameters()->find("ssid")->getString();
    key_string = object.getParameters()->find("key")->getString();

    /////////////////////////////////////////
    // create coda

    // Read ID from invocation. ID is returned in coda response.
    uint32_t invocationID = object.getID();

    // create coda and pass to Voytalk hub
    VoytalkCoda coda(invocationID, 1);
    hub.processCoda(coda);

    // change state in main application
    state |= FLAG_PROVISIONED;

    // change state inside Voytalk hub
    hub.setStateMask(state);
}

/*****************************************************************************/
/* Reset device example                                                      */
/*****************************************************************************/

void resetIntentConstruction(VoytalkHub& hub)
{
    DEBUGOUT("main: reset intent construction\r\n");

    /* create intent using generated endpoint and constraint set */
    VoytalkIntent intent("com.arm.reset");

    /* serialize object tree to CBOR */
    hub.processIntent(intent);
}

void resetIntentInvocation(VoytalkHub& hub, VoytalkIntentInvocation& object)
{
    DEBUGOUT("main: reset invocation\r\n");

    // print object tree
    object.print();

    /////////////////////////////////////////
    // create coda

    // Read ID from invocation. ID is returned in coda response.
    uint32_t invocationID = object.getID();

    // create coda and pass to Voytalk hub
    VoytalkCoda coda(invocationID, 1);
    hub.processCoda(coda);

    // change state in main application
    state &= ~FLAG_PROVISIONED;

    // change state inside Voytalk hub
    hub.setStateMask(state);
}

/*****************************************************************************/
/* Voytalk complex example                                                   */
/*****************************************************************************/

/*
    Callback functions for the example intent.
*/
void exampleIntentConstruction(VoytalkHub& hub)
{
    DEBUGOUT("main: complex example intent construction\r\n");

    /* create intent */
    VoytalkIntent intent("com.arm.examples.complex");

    /* serialize object tree to CBOR */
    hub.processIntent(intent);
}

void exampleIntentInvocation(VoytalkHub& hub, VoytalkIntentInvocation& object)
{
    DEBUGOUT("main: complex example invocation\r\n");

    // print object tree
    object.print();

    // Read ID from invocation. ID is returned in coda response.
    uint32_t invocationID = object.getID();

    // create coda and pass to Voytalk hub
    VoytalkCoda coda(invocationID, 1);
    hub.processCoda(coda);
}

/*****************************************************************************/
/* Voytalk custom example                                                    */
/*****************************************************************************/

void customIntentConstruction(VoytalkHub& hub)
{
    DEBUGOUT("main: custom intent construction\r\n");

    /*  Define custom constraints.
        Note: constraints can be nested.
    */

    /* ssid, key are level 0 variables */
    VoytalkConstraint L0_ssid("Network Name",
                              VoytalkConstraint::TypeString,
                              "ssid");

    VoytalkConstraint L0_key("Password",
                             VoytalkConstraint::TypeString,
                             "key");

    /* combine level 0 variables */
    VoytalkConstraint* properties[] = { &L0_ssid,
                                        &L0_key };

    // define level 0
    VoytalkConstraint constraints("Custom Access",
                                  properties);

    /* optional: default values */
    L0_ssid.setDefaultValue("homehub");

    /* optional: description fields */
    L0_ssid.setDescription("The name of the network you want to connect to.");
    L0_key.setDescription("The password for the network.");

    constraints.setDescription("The device wants to access your Wifi network.");

    /* create intent using generated endpoint and constraint set */
    VoytalkIntent intent("com.arm.examples.custom", constraints);

    /* serialize object tree to CBOR */
    hub.processIntent(intent);
}

void customIntentInvocation(VoytalkHub& hub, VoytalkIntentInvocation& object)
{
    DEBUGOUT("main: custom example invocation\r\n");

    // print object tree
    object.print();

    // Read ID from invocation. ID is returned in coda response.
    uint32_t invocationID = object.getID();

    // create coda and pass to Voytalk hub
    VoytalkCoda coda(invocationID, 1);
    hub.processCoda(coda);
}

/*****************************************************************************/
/* main                                                                      */
/*****************************************************************************/

void app_start(int, char *[])
{
    /*
        Register Voytalk intents in the hub.

        First parameter is the callback function for intent generation.
        Second is the callback function for when the intent is invoked.
        Third parameter is a bitmap for grouping intents together.
    */

    // Wifi provisioning intent
    vthub.registerIntent(wifiIntentConstruction,
                         wifiIntentInvocation,
                         FLAG_CONNECTED | FLAG_PROVISIONED);

    // reset intent
    vthub.registerIntent(resetIntentConstruction,
                         resetIntentInvocation,
                         FLAG_PROVISIONED);

    // custom intent
#if 0
    vthub.registerIntent(customIntentConstruction,
                         customIntentInvocation,
                         FLAG_CONNECTED | FLAG_PROVISIONED);
#endif

    /*
        Set the current state mask.

        Mask is AND'ed with each intent's bitmap and only intents with non-zero
        results are displayed and can be invoked.
    */
    vthub.setStateMask(0);

    /*************************************************************************/
    /*************************************************************************/
    /* bluetooth le */
    ble.init();

    // status callback functions
    ble.gap().onConnection(whenConnected);
    ble.gap().onDisconnection(whenDisconnected);

    /* construct advertising beacon */
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED|GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME, (const uint8_t *) DEVICE_NAME, sizeof(DEVICE_NAME) - 1);
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, uuid.getBaseUUID(), uuid.getLen());
    ble.gap().accumulateAdvertisingPayloadTxPower(CFG_BLE_TX_POWER_LEVEL);

    ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
    ble.gap().setAdvertisingInterval(1000); /* 1s; in multiples of 0.625ms. */

    // set TX power
    ble.gap().setTxPower(CFG_BLE_TX_POWER_LEVEL);

    // Apple uses device name instead of beacon name
    ble.gap().setDeviceName((const uint8_t*) DEVICE_NAME);

    /*************************************************************************/
    /*************************************************************************/
    // setup block transfer service

    // add service using ble device, responding to uuid, and without encryption
    bts.init(uuid, SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK);

    // set callback functions for the BlockTransfer service
    bts.setWriteAuthorizationCallback(blockServerWriteHandler);
    bts.setReadAuthorizationCallback(blockServerReadHandler);

    // ble setup complete - start advertising
    ble.gap().startAdvertising();

    printf("Voytalk Test: %s %s\r\n", __DATE__, __TIME__);
}

/*****************************************************************************/
/* Compatibility                                                             */
/*****************************************************************************/

#if defined(YOTTA_MINAR_VERSION_STRING)
/*********************************************************/
/* Build for mbed OS                                     */
/*********************************************************/

void signalReady()
{
    minar::Scheduler::postCallback(blockServerSendNotification);
}

#else
/*********************************************************/
/* Build for mbed Classic                                */
/*********************************************************/

bool sendNotification = false;

void signalReady()
{
    sendNotification = true;
}

int main(void)
{
    app_start(0, NULL);

    for(;;)
    {
        // send notification outside of interrupt context
        if (sendNotification)
        {
            sendNotification = false;
            blockServerSendNotification();
        }

        ble.waitForEvent();
    }
}
#endif

<commit_msg>start update to new API<commit_after>/* mbed Microcontroller Library
 * Copyright (c) 2006-2015 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "mbed.h"
#include "ble/BLE.h"
#include "ble-blocktransfer/BlockTransferService.h"
#include "voytalk/Voytalk.h"

/*****************************************************************************/
/* Configuration                                                             */
/*****************************************************************************/

// set device name
const char DEVICE_NAME[] = "Testvoy";

// set TX power
#ifndef CFG_BLE_TX_POWER_LEVEL
#define CFG_BLE_TX_POWER_LEVEL 0
#endif

// control debug output
#if 1
#define DEBUGOUT(...) { printf(__VA_ARGS__); }
#else
#define DEBUGOUT(...) /* nothing */
#endif // DEBUGOUT

/*****************************************************************************/

/* Voytalk short UUID */
const UUID uuid(0xFE8E);

/* Voytalk states */
typedef enum {
    FLAG_CONNECTED      = 0x01,
    FLAG_PROVISIONED    = 0x02,
} flags_t;

static volatile uint8_t state;

/*****************************************************************************/
/* Global variables used by the test app                                     */
/*****************************************************************************/

// BLE_API ble device
BLE ble;

// Transfer large blocks of data on platforms without Fragmentation-And-Recombination
BlockTransferService bts;

// Voytalk handling
VoytalkRouter router(DEVICE_NAME);

// buffer for sending and receiving data
SharedPointer<Block> writeBlock;
uint8_t readBuffer[1000];
BlockStatic readBlock(readBuffer, sizeof(readBuffer));

// wifi parameters
std::string ssid_string;
std::string key_string;

// Compatibility function
void signalReady();

/*****************************************************************************/
/* Functions for handling debug output                                       */
/*****************************************************************************/

/*
    Functions called when BLE device connects and disconnects.
*/
void whenConnected(const Gap::ConnectionCallbackParams_t* params)
{
    (void) params;
    DEBUGOUT("main: Connected: %d %d %d\r\n", params->connectionParams->minConnectionInterval,
                                              params->connectionParams->maxConnectionInterval,
                                              params->connectionParams->slaveLatency);

    // change state in main application
    state |= FLAG_CONNECTED;

    // change state inside Voytalk hub
    router.setStateMask(state);
}

void whenDisconnected(const Gap::DisconnectionCallbackParams_t*)
{
    DEBUGOUT("main: Disconnected!\r\n");
    DEBUGOUT("main: Restarting the advertising process\r\n");

    ble.gap().startAdvertising();

    // change state in main application
    state &= ~FLAG_CONNECTED;

    // change state inside Voytalk hub
    router.setStateMask(state);
}

/*****************************************************************************/
/* BlockTransfer callbacks for sending and receiving data                    */
/*****************************************************************************/

/*
    Function called when signaling client that new data is ready to be read.
*/
void blockServerSendNotification()
{
    DEBUGOUT("main: notify read updated\r\n");
    bts.updateCharacteristicValue((uint8_t*)"", 0);
}

/*
    Function called when device receives a read request over BLE.
*/
SharedPointer<Block> blockServerReadHandler(uint32_t offset)
{
    DEBUGOUT("main: block read\r\n");
    (void) offset;

    return SharedPointer<Block>(new BlockStatic(readBlock));
}

/*
    Function called when data has been written over BLE.
*/
void blockServerWriteHandler(SharedPointer<Block> block)
{
    DEBUGOUT("main: block write\r\n");

    /*
        Process received data, assuming it is CBOR encoded.
        Any output generated will be written to the readBlock.
    */
    router.processCBOR((BlockStatic*) block.get(), &readBlock);

    /*
        If the readBlock length is non-zero it means a reply has been generated.
    */
    if (readBlock.getLength() > 0)
    {
        signalReady();
    }
}

/*****************************************************************************/
/* Voytalk Wifi example                                                      */
/*****************************************************************************/

/*
    Callback function for constructing wifi intent.
*/
void wifiIntentConstruction(VTRequest& req, VTResponse& res)
{
    DEBUGOUT("main: wifi intent construction\r\n");
    /* create intent using generated endpoint and constraint set */
    VTIntent intent("com.arm.connectivity.wifi");
    intent.knownParameters("/networks");

    res.write(intent);
}
/*
void wifiIntentInvocation(VoytalkHub& hub, VoytalkIntentInvocation& object)
{
    DEBUGOUT("main: wifi invocation\r\n");

    // debug: print object tree
    object.print();

    /////////////////////////////////////////
    // retrieve parameters
    ssid_string = object.getParameters()->find("ssid")->getString();
    key_string = object.getParameters()->find("key")->getString();

    /////////////////////////////////////////
    // create coda

    // Read ID from invocation. ID is returned in coda response.
    uint32_t invocationID = object.getID();

    // create coda and pass to Voytalk hub
    VoytalkCoda coda(invocationID, 1);
    hub.processCoda(coda);

    // change state in main application
    state |= FLAG_PROVISIONED;

    // change state inside Voytalk hub
    hub.setStateMask(state);
}*/

/*****************************************************************************/
/* Reset device example                                                      */
/*****************************************************************************/

void resetIntentConstruction(VTRequest& req, VTResponse& res)
{
    DEBUGOUT("main: reset intent construction\r\n");

    /* create intent using generated endpoint and constraint set */
    VTIntent intent("com.arm.reset");

    res.write(intent);
}
/*
void resetIntentInvocation(VoytalkHub& hub, VoytalkIntentInvocation& object)
{
    DEBUGOUT("main: reset invocation\r\n");

    // print object tree
    object.print();

    /////////////////////////////////////////
    // create coda

    // Read ID from invocation. ID is returned in coda response.
    uint32_t invocationID = object.getID();

    // create coda and pass to Voytalk hub
    VoytalkCoda coda(invocationID, 1);
    hub.processCoda(coda);

    // change state in main application
    state &= ~FLAG_PROVISIONED;

    // change state inside Voytalk hub
    hub.setStateMask(state);
}
*/

/*****************************************************************************/
/* Voytalk complex example                                                   */
/*****************************************************************************/

/*
    Callback functions for the example intent.
*/
void exampleIntentConstruction(VTRequest& req, VTResponse& res)
{
    DEBUGOUT("main: complex example intent construction\r\n");

    /* create intent */
    VTIntent intent("com.arm.examples.complex");

    res.write(intent);
}
/*
void exampleIntentInvocation(VoytalkHub& hub, VoytalkIntentInvocation& object)
{
    DEBUGOUT("main: complex example invocation\r\n");

    // print object tree
    object.print();

    // Read ID from invocation. ID is returned in coda response.
    uint32_t invocationID = object.getID();

    // create coda and pass to Voytalk hub
    VoytalkCoda coda(invocationID, 1);
    hub.processCoda(coda);
}
*/

/*****************************************************************************/
/* Voytalk custom example                                                    */
/*****************************************************************************/

void customIntentConstruction(VTRequest& req, VTResponse& res)
{
    DEBUGOUT("main: custom intent construction\r\n");

    // /*  Define custom constraints.
    //     Note: constraints can be nested.
    // */

    // /* ssid, key are level 0 variables */
    // VoytalkConstraint L0_ssid("Network Name",
    //                           VoytalkConstraint::TypeString,
    //                           "ssid");

    // VoytalkConstraint L0_key("Password",
    //                          VoytalkConstraint::TypeString,
    //                          "key");

    // /* combine level 0 variables */
    // VoytalkConstraint* properties[] = { &L0_ssid,
    //                                     &L0_key };

    // // define level 0
    // VoytalkConstraint constraints("Custom Access",
    //                               properties);

    // /* optional: default values */
    // L0_ssid.setDefaultValue("homehub");

    // /* optional: description fields */
    // L0_ssid.setDescription("The name of the network you want to connect to.");
    // L0_key.setDescription("The password for the network.");

    // constraints.setDescription("The device wants to access your Wifi network.");

    // /* create intent using generated endpoint and constraint set */
    // VTIntent intent("com.arm.examples.custom", constraints);

    // callback(200, intent);
}
/*
void customIntentInvocation(VoytalkHub& hub, VoytalkIntentInvocation& object)
{
    DEBUGOUT("main: custom example invocation\r\n");

    // print object tree
    object.print();

    // Read ID from invocation. ID is returned in coda response.
    uint32_t invocationID = object.getID();

    // create coda and pass to Voytalk hub
    VoytalkCoda coda(invocationID, 1);
    hub.processCoda(coda);
}*/

void networkListResource(VTRequest& req, VTResponse& res, VoytalkRouter::done_t done)
{
    DEBUGOUT("listing network resources");

    VoytalkKnownParameters parameters(res, 2);

    parameters.parameter("com.arm.connectivity.wifi", 50)
        .map(2)
            .item("ssid", "miWifi")
            .item("key", "supersecurepassword");

    parameters.parameter("com.arm.connectivity.wifi", 20)
        .map(2)
            .item("ssid", "yoWifi")
            .item("key", "securepasswordinit");

    done(200);
}

/*****************************************************************************/
/* main                                                                      */
/*****************************************************************************/

void app_start(int, char *[])
{
    /*
        Register Voytalk intents in the hub.

        First parameter is the callback function for intent generation.
        Second is the callback function for when the intent is invoked.
        Third parameter is a bitmap for grouping intents together.
    */

    // Wifi provisioning intent
    router.registerIntent(wifiIntentConstruction,
                          FLAG_CONNECTED | FLAG_PROVISIONED);

    // reset intent
    router.registerIntent(resetIntentConstruction,
                          FLAG_PROVISIONED);

    // custom intent
#if 0
    router.registerIntent(customIntentConstruction,
                         FLAG_CONNECTED | FLAG_PROVISIONED);
#endif

    /*
        Set the current state mask.

        Mask is AND'ed with each intent's bitmap and only intents with non-zero
        results are displayed and can be invoked.
    */
    router.setStateMask(0);

    /*
        Define some resource callbacks
    */

    router.get("/networks", networkListResource);
    router.post("/otherthing", networkListResource);

    /*************************************************************************/
    /*************************************************************************/
    /* bluetooth le */
    ble.init();

    // status callback functions
    ble.gap().onConnection(whenConnected);
    ble.gap().onDisconnection(whenDisconnected);

    /* construct advertising beacon */
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED|GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME, (const uint8_t *) DEVICE_NAME, sizeof(DEVICE_NAME) - 1);
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, uuid.getBaseUUID(), uuid.getLen());
    ble.gap().accumulateAdvertisingPayloadTxPower(CFG_BLE_TX_POWER_LEVEL);

    ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
    ble.gap().setAdvertisingInterval(1000); /* 1s; in multiples of 0.625ms. */

    // set TX power
    ble.gap().setTxPower(CFG_BLE_TX_POWER_LEVEL);

    // Apple uses device name instead of beacon name
    ble.gap().setDeviceName((const uint8_t*) DEVICE_NAME);

    /*************************************************************************/
    /*************************************************************************/
    // setup block transfer service

    // add service using ble device, responding to uuid, and without encryption
    bts.init(uuid, SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK);

    // set callback functions for the BlockTransfer service
    bts.setWriteAuthorizationCallback(blockServerWriteHandler);
    bts.setReadAuthorizationCallback(blockServerReadHandler);

    // ble setup complete - start advertising
    ble.gap().startAdvertising();

    printf("Voytalk Test: %s %s\r\n", __DATE__, __TIME__);
}

/*****************************************************************************/
/* Compatibility                                                             */
/*****************************************************************************/

#if defined(YOTTA_MINAR_VERSION_STRING)
/*********************************************************/
/* Build for mbed OS                                     */
/*********************************************************/

void signalReady()
{
    minar::Scheduler::postCallback(blockServerSendNotification);
}

#else
/*********************************************************/
/* Build for mbed Classic                                */
/*********************************************************/

bool sendNotification = false;

void signalReady()
{
    sendNotification = true;
}

int main(void)
{
    app_start(0, NULL);

    for(;;)
    {
        // send notification outside of interrupt context
        if (sendNotification)
        {
            sendNotification = false;
            blockServerSendNotification();
        }

        ble.waitForEvent();
    }
}
#endif

<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2011, Image Engine Design Inc. All rights reserved.
//  Copyright (c) 2012, John Haddon. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
//     * Neither the name of Image Engine Design nor the names of any
//       other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  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 OWNER 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 <stdio.h>

#include "ai_drivers.h"
#include "ai_version.h"

#include "IECore/DisplayDriver.h"
#include "IECore/BoxAlgo.h"
#include "IECore/SimpleTypedData.h"
#include "IECore/MessageHandler.h"

#include "IECoreArnold/ParameterAlgo.h"

using namespace Imath;
using namespace IECore;
using namespace IECoreArnold;

namespace
{

// Stores a Cortex DisplayDriver and the parameters
// used to create it. This forms the private data
// accessed via AiDriverGetLocalData.
struct LocalData
{
	DisplayDriverPtr displayDriver;
	ConstCompoundDataPtr displayDriverParameters;

	void imageClose()
	{
		if( !displayDriver )
		{
			return;
		}

		try
		{
			displayDriver->imageClose();
		}
		catch( const std::exception &e )
		{
			// We have to catch and report exceptions because letting them out into pure c land
			// just causes aborts.
			msg( Msg::Error, "ieOutputDriver:driverClose", e.what() );
		}
		displayDriver = NULL;
	}

};

void driverParameters( AtList *params, AtMetaDataStore *metaData )
{
	AiParameterSTR( "driverType", "" );

	// we need to specify this metadata to keep MtoA happy.
	AiMetaDataSetStr( metaData, 0, "maya.attr_prefix", "" );
	AiMetaDataSetStr( metaData, 0, "maya.translator", "ie" );
}

void driverInitialize( AtNode *node, AtParamValue *parameters )
{
	AiDriverInitialize( node, true, new LocalData );
}

void driverUpdate( AtNode *node, AtParamValue *parameters )
{
}

bool driverSupportsPixelType( const AtNode *node, AtByte pixelType )
{
	switch( pixelType )
	{
		case AI_TYPE_RGB :
		case AI_TYPE_RGBA :
		case AI_TYPE_FLOAT :
		case AI_TYPE_VECTOR :
		case AI_TYPE_POINT :
			return true;
		default:
			return false;
	}
}

const char **driverExtension()
{
   return 0;
}

void driverOpen( AtNode *node, struct AtOutputIterator *iterator, AtBBox2 displayWindow, AtBBox2 dataWindow, int bucketSize )
{
	std::vector<std::string> channelNames;

	const char *name = 0;
	int pixelType = 0;
	while( AiOutputIteratorGetNext( iterator, &name, &pixelType, 0 ) )
	{
		std::string namePrefix;
		if( strcmp( name, "RGB" ) && strcmp( name, "RGBA" ) )
		{
			namePrefix = std::string( name ) + ".";
		}

		switch( pixelType )
		{
			case AI_TYPE_RGB :
			case AI_TYPE_VECTOR :
			case AI_TYPE_POINT :
				channelNames.push_back( namePrefix + "R" );
				channelNames.push_back( namePrefix + "G" );
				channelNames.push_back( namePrefix + "B" );
				break;
			case AI_TYPE_RGBA :
				channelNames.push_back( namePrefix + "R" );
				channelNames.push_back( namePrefix + "G" );
				channelNames.push_back( namePrefix + "B" );
				channelNames.push_back( namePrefix + "A" );
				break;
			case AI_TYPE_FLOAT :
				// no need for prefix because it's not a compound type
				channelNames.push_back( name );
				break;
		}
	}

	/// \todo Make Convert.h
	Box2i cortexDisplayWindow(
		V2i( displayWindow.minx, displayWindow.miny ),
		V2i( displayWindow.maxx, displayWindow.maxy )
	);

	Box2i cortexDataWindow(
		V2i( dataWindow.minx, dataWindow.miny ),
		V2i( dataWindow.maxx, dataWindow.maxy )
	);

	CompoundDataPtr parameters = new CompoundData();
	ParameterAlgo::getParameters( node, parameters->writable() );

	// IECore::DisplayDriver lacks any official mechanism for passing
	// the pixel aspect ratio, so for now we just pass it via the
	// parameters. We should probably move GafferImage::Format to
	// IECoreImage::Format and then use that in place of the display
	// window.
	parameters->writable()["pixelAspect"] = new FloatData(
		// Arnold is y/x, we're x/y
		1.0f / AiNodeGetFlt( AiUniverseGetOptions(), "aspect_ratio" )
	);

	const std::string driverType = AiNodeGetStr( node, "driverType" );

	LocalData *localData = (LocalData *)AiDriverGetLocalData( node );

	// We reuse the previous driver if we can - this allows us to use
	// the same driver for every stage of a progressive render.
	if( localData->displayDriver )
	{
		if(
			localData->displayDriver->typeName() == driverType &&
			localData->displayDriver->displayWindow() == cortexDisplayWindow &&
			localData->displayDriver->dataWindow() == cortexDataWindow &&
			localData->displayDriver->channelNames() == channelNames &&
			localData->displayDriverParameters->isEqualTo( parameters.get() )
		)
		{
			// Can reuse
			return;
		}
		else
		{
			// Can't reuse, so must close before making a new one.
			localData->imageClose();
		}
	}

	// Couldn't reuse a driver, so create one from scratch.
	try
	{
		localData->displayDriver = IECore::DisplayDriver::create( driverType, cortexDisplayWindow, cortexDataWindow, channelNames, parameters );
		localData->displayDriverParameters = parameters;
	}
	catch( const std::exception &e )
	{
		// We have to catch and report exceptions because letting them out into pure c land
		// just causes aborts.
		msg( Msg::Error, "ieOutputDriver:driverOpen", e.what() );
	}
}

bool driverNeedsBucket( AtNode *node, int x, int y, int sx, int sy, int tId )
{
	return true;
}

void driverPrepareBucket( AtNode *node, int x, int y, int sx, int sy, int tId )
{
}

void driverProcessBucket( AtNode *node, struct AtOutputIterator *iterator, struct AtAOVSampleIterator *sample_iterator, int x, int y, int sx, int sy, int tId )
{
}

void driverWriteBucket( AtNode *node, struct AtOutputIterator *iterator, struct AtAOVSampleIterator *sampleIterator, int x, int y, int sx, int sy )
{
	LocalData *localData = (LocalData *)AiDriverGetLocalData( node );
	if( !localData->displayDriver )
	{
		return;
	}

	const int numOutputChannels = localData->displayDriver->channelNames().size();

	std::vector<float> interleavedData;
	interleavedData.resize( sx * sy * numOutputChannels );

	int pixelType = 0;
	const void *bucketData;
	int outChannelOffset = 0;
	while( AiOutputIteratorGetNext( iterator, 0, &pixelType, &bucketData ) )
	{
		int numChannels = 0;
		switch( pixelType )
		{
			case AI_TYPE_RGB :
			case AI_TYPE_VECTOR :
			case AI_TYPE_POINT :
				numChannels = 3;
				break;
			case AI_TYPE_RGBA :
				numChannels = 4;
				break;
			case AI_TYPE_FLOAT :
				numChannels = 1;
				break;
		}

		for( int c = 0; c < numChannels; c++ )
		{
			float *in = (float *)(bucketData) + c;
			float *out = &(interleavedData[0]) + outChannelOffset;
			for( int j = 0; j < sy; j++ )
			{
				for( int i = 0; i < sx; i++ )
				{
					*out = *in;
					out += numOutputChannels;
					in += numChannels;
				}
			}
			outChannelOffset += 1;
		}

	}

	Box2i bucketBox(
		V2i( x, y ),
		V2i( x + sx - 1, y + sy - 1 )
	);

	try
	{
		localData->displayDriver->imageData( bucketBox, &(interleavedData[0]), interleavedData.size() );
	}
	catch( const std::exception &e )
	{
		// we have to catch and report exceptions because letting them out into pure c land
		// just causes aborts.
		msg( Msg::Error, "ieOutputDriver:driverWriteBucket", e.what() );
	}
}

void driverClose( AtNode *node, struct AtOutputIterator *iterator )
{
	LocalData *localData = (LocalData *)AiDriverGetLocalData( node );
	// We only close the display immediately if it doesn't accept
	// repeated data (progressive renders). This is so we can reuse it in
	// driverOpen if it appears that a progressive render is taking place.
	if( localData->displayDriver && !localData->displayDriver->acceptsRepeatedData() )
	{
		localData->imageClose();
	}
}

void driverFinish( AtNode *node )
{
	LocalData *localData = (LocalData *)AiDriverGetLocalData( node );
	// Perform any pending close we may have deferred in driverClose().
	localData->imageClose();
	delete localData;
	AiDriverDestroy( node );
}

} // namespace

AI_EXPORT_LIB bool NodeLoader( int i, AtNodeLib *node )
{
	if( i==0 )
	{
		static AtCommonMethods commonMethods = {
			driverParameters,
			driverInitialize,
			driverUpdate,
			driverFinish
		};
		static AtDriverNodeMethods driverMethods = {
			driverSupportsPixelType,
			driverExtension,
			driverOpen,
			driverNeedsBucket,
			driverPrepareBucket,
			driverProcessBucket,
			driverWriteBucket,
			driverClose
		};
		static AtNodeMethods nodeMethods = {
			&commonMethods,
			&driverMethods
		};

		node->node_type = AI_NODE_DRIVER;
		node->output_type = AI_TYPE_NONE;
		node->name = "ieDisplay";
		node->methods = &nodeMethods;
		sprintf( node->version, AI_VERSION );

		return true;
	}

	return false;
}
<commit_msg>Arnold output driver : Don't reformat data unless necessary<commit_after>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2011, Image Engine Design Inc. All rights reserved.
//  Copyright (c) 2012, John Haddon. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
//     * Neither the name of Image Engine Design nor the names of any
//       other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  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 OWNER 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 <stdio.h>

#include "ai_drivers.h"
#include "ai_version.h"

#include "IECore/DisplayDriver.h"
#include "IECore/BoxAlgo.h"
#include "IECore/SimpleTypedData.h"
#include "IECore/MessageHandler.h"

#include "IECoreArnold/ParameterAlgo.h"

using namespace Imath;
using namespace IECore;
using namespace IECoreArnold;

namespace
{

// Stores a Cortex DisplayDriver and the parameters
// used to create it. This forms the private data
// accessed via AiDriverGetLocalData.
struct LocalData
{

	LocalData()
		:	numOutputs( 0 )
	{
	}

	DisplayDriverPtr displayDriver;
	ConstCompoundDataPtr displayDriverParameters;
	int numOutputs;

	void imageClose()
	{
		if( !displayDriver )
		{
			return;
		}

		try
		{
			displayDriver->imageClose();
		}
		catch( const std::exception &e )
		{
			// We have to catch and report exceptions because letting them out into pure c land
			// just causes aborts.
			msg( Msg::Error, "ieOutputDriver:driverClose", e.what() );
		}
		displayDriver = NULL;
	}

};

void driverParameters( AtList *params, AtMetaDataStore *metaData )
{
	AiParameterSTR( "driverType", "" );

	// we need to specify this metadata to keep MtoA happy.
	AiMetaDataSetStr( metaData, 0, "maya.attr_prefix", "" );
	AiMetaDataSetStr( metaData, 0, "maya.translator", "ie" );
}

void driverInitialize( AtNode *node, AtParamValue *parameters )
{
	AiDriverInitialize( node, true, new LocalData );
}

void driverUpdate( AtNode *node, AtParamValue *parameters )
{
}

bool driverSupportsPixelType( const AtNode *node, AtByte pixelType )
{
	switch( pixelType )
	{
		case AI_TYPE_RGB :
		case AI_TYPE_RGBA :
		case AI_TYPE_FLOAT :
		case AI_TYPE_VECTOR :
		case AI_TYPE_POINT :
			return true;
		default:
			return false;
	}
}

const char **driverExtension()
{
   return 0;
}

void driverOpen( AtNode *node, struct AtOutputIterator *iterator, AtBBox2 displayWindow, AtBBox2 dataWindow, int bucketSize )
{
	LocalData *localData = (LocalData *)AiDriverGetLocalData( node );
	localData->numOutputs = 0;

	std::vector<std::string> channelNames;

	const char *name = 0;
	int pixelType = 0;
	while( AiOutputIteratorGetNext( iterator, &name, &pixelType, 0 ) )
	{
		std::string namePrefix;
		if( strcmp( name, "RGB" ) && strcmp( name, "RGBA" ) )
		{
			namePrefix = std::string( name ) + ".";
		}

		switch( pixelType )
		{
			case AI_TYPE_RGB :
			case AI_TYPE_VECTOR :
			case AI_TYPE_POINT :
				channelNames.push_back( namePrefix + "R" );
				channelNames.push_back( namePrefix + "G" );
				channelNames.push_back( namePrefix + "B" );
				break;
			case AI_TYPE_RGBA :
				channelNames.push_back( namePrefix + "R" );
				channelNames.push_back( namePrefix + "G" );
				channelNames.push_back( namePrefix + "B" );
				channelNames.push_back( namePrefix + "A" );
				break;
			case AI_TYPE_FLOAT :
				// no need for prefix because it's not a compound type
				channelNames.push_back( name );
				break;
		}
		localData->numOutputs += 1;
	}

	/// \todo Make Convert.h
	Box2i cortexDisplayWindow(
		V2i( displayWindow.minx, displayWindow.miny ),
		V2i( displayWindow.maxx, displayWindow.maxy )
	);

	Box2i cortexDataWindow(
		V2i( dataWindow.minx, dataWindow.miny ),
		V2i( dataWindow.maxx, dataWindow.maxy )
	);

	CompoundDataPtr parameters = new CompoundData();
	ParameterAlgo::getParameters( node, parameters->writable() );

	// IECore::DisplayDriver lacks any official mechanism for passing
	// the pixel aspect ratio, so for now we just pass it via the
	// parameters. We should probably move GafferImage::Format to
	// IECoreImage::Format and then use that in place of the display
	// window.
	parameters->writable()["pixelAspect"] = new FloatData(
		// Arnold is y/x, we're x/y
		1.0f / AiNodeGetFlt( AiUniverseGetOptions(), "aspect_ratio" )
	);

	const std::string driverType = AiNodeGetStr( node, "driverType" );

	// We reuse the previous driver if we can - this allows us to use
	// the same driver for every stage of a progressive render.
	if( localData->displayDriver )
	{
		if(
			localData->displayDriver->typeName() == driverType &&
			localData->displayDriver->displayWindow() == cortexDisplayWindow &&
			localData->displayDriver->dataWindow() == cortexDataWindow &&
			localData->displayDriver->channelNames() == channelNames &&
			localData->displayDriverParameters->isEqualTo( parameters.get() )
		)
		{
			// Can reuse
			return;
		}
		else
		{
			// Can't reuse, so must close before making a new one.
			localData->imageClose();
		}
	}

	// Couldn't reuse a driver, so create one from scratch.
	try
	{
		localData->displayDriver = IECore::DisplayDriver::create( driverType, cortexDisplayWindow, cortexDataWindow, channelNames, parameters );
		localData->displayDriverParameters = parameters;
	}
	catch( const std::exception &e )
	{
		// We have to catch and report exceptions because letting them out into pure c land
		// just causes aborts.
		msg( Msg::Error, "ieOutputDriver:driverOpen", e.what() );
	}
}

bool driverNeedsBucket( AtNode *node, int x, int y, int sx, int sy, int tId )
{
	return true;
}

void driverPrepareBucket( AtNode *node, int x, int y, int sx, int sy, int tId )
{
}

void driverProcessBucket( AtNode *node, struct AtOutputIterator *iterator, struct AtAOVSampleIterator *sample_iterator, int x, int y, int sx, int sy, int tId )
{
}

void driverWriteBucket( AtNode *node, struct AtOutputIterator *iterator, struct AtAOVSampleIterator *sampleIterator, int x, int y, int sx, int sy )
{
	LocalData *localData = (LocalData *)AiDriverGetLocalData( node );
	if( !localData->displayDriver )
	{
		return;
	}

	const int numOutputChannels = localData->displayDriver->channelNames().size();

	const float *imageData;
	std::vector<float> interleavedData;
	if( localData->numOutputs == 1 )
	{
		// Data already has the layout we need.
		const void *bucketData;
		AiOutputIteratorGetNext( iterator, NULL, NULL, &bucketData );
		imageData = (float *)bucketData;
	}
	else
	{
		// We need to interleave multiple outputs
		// into a single block for the display driver.
		interleavedData.resize( sx * sy * numOutputChannels );

		int pixelType = 0;
		const void *bucketData;
		int outChannelOffset = 0;
		while( AiOutputIteratorGetNext( iterator, 0, &pixelType, &bucketData ) )
		{
			int numChannels = 0;
			switch( pixelType )
			{
				case AI_TYPE_RGB :
				case AI_TYPE_VECTOR :
				case AI_TYPE_POINT :
					numChannels = 3;
					break;
				case AI_TYPE_RGBA :
					numChannels = 4;
					break;
				case AI_TYPE_FLOAT :
					numChannels = 1;
					break;
			}

			for( int c = 0; c < numChannels; c++ )
			{
				float *in = (float *)(bucketData) + c;
				float *out = &(interleavedData[0]) + outChannelOffset;
				for( int j = 0; j < sy; j++ )
				{
					for( int i = 0; i < sx; i++ )
					{
						*out = *in;
						out += numOutputChannels;
						in += numChannels;
					}
				}
				outChannelOffset += 1;
			}
		}

		imageData = &interleavedData[0];
	}

	Box2i bucketBox(
		V2i( x, y ),
		V2i( x + sx - 1, y + sy - 1 )
	);

	try
	{
		localData->displayDriver->imageData( bucketBox, imageData, sx * sy * numOutputChannels );
	}
	catch( const std::exception &e )
	{
		// we have to catch and report exceptions because letting them out into pure c land
		// just causes aborts.
		msg( Msg::Error, "ieOutputDriver:driverWriteBucket", e.what() );
	}
}

void driverClose( AtNode *node, struct AtOutputIterator *iterator )
{
	LocalData *localData = (LocalData *)AiDriverGetLocalData( node );
	// We only close the display immediately if it doesn't accept
	// repeated data (progressive renders). This is so we can reuse it in
	// driverOpen if it appears that a progressive render is taking place.
	if( localData->displayDriver && !localData->displayDriver->acceptsRepeatedData() )
	{
		localData->imageClose();
	}
}

void driverFinish( AtNode *node )
{
	LocalData *localData = (LocalData *)AiDriverGetLocalData( node );
	// Perform any pending close we may have deferred in driverClose().
	localData->imageClose();
	delete localData;
	AiDriverDestroy( node );
}

} // namespace

AI_EXPORT_LIB bool NodeLoader( int i, AtNodeLib *node )
{
	if( i==0 )
	{
		static AtCommonMethods commonMethods = {
			driverParameters,
			driverInitialize,
			driverUpdate,
			driverFinish
		};
		static AtDriverNodeMethods driverMethods = {
			driverSupportsPixelType,
			driverExtension,
			driverOpen,
			driverNeedsBucket,
			driverPrepareBucket,
			driverProcessBucket,
			driverWriteBucket,
			driverClose
		};
		static AtNodeMethods nodeMethods = {
			&commonMethods,
			&driverMethods
		};

		node->node_type = AI_NODE_DRIVER;
		node->output_type = AI_TYPE_NONE;
		node->name = "ieDisplay";
		node->methods = &nodeMethods;
		sprintf( node->version, AI_VERSION );

		return true;
	}

	return false;
}
<|endoftext|>


<commit_before>#include "Mocks.hpp"

namespace testing {

enum class level : std::uint8_t { debug, info, warn, error };

} // namespace testing

namespace blackhole { namespace sink {

template<>
struct priority_traits<testing::level> {
    static inline
    priority_t map(testing::level lvl) {
        switch (lvl) {
        case testing::level::debug:
            return priority_t::debug;
        case testing::level::info:
            return priority_t::info;
        case testing::level::warn:
            return priority_t::warning;
        case testing::level::error:
            return priority_t::err;
        }
    }
};

} } // namespace blackhole::sink

namespace blackhole {

struct formatter_config_t {
    std::string type;
    std::map<std::string, std::string> args;
};

struct sink_config_t {
    std::string type;
    std::map<std::string, std::string> args;
};

namespace factory {

template<typename Level, typename Sink>
std::unique_ptr<base_frontend_t> create(const formatter_config_t& formatter_config, std::unique_ptr<Sink> sink) {
    if (formatter_config.type == "string") {
        typedef formatter::string_t formatter_type;

        std::string pattern = formatter_config.args.at("pattern");
        auto formatter = std::make_unique<formatter_type>(pattern);

        return std::make_unique<frontend_t<formatter_type, Sink, Level>>(std::move(formatter), std::move(sink));
    }

    return std::unique_ptr<base_frontend_t>();
}

template<typename Level>
std::unique_ptr<base_frontend_t> create(const formatter_config_t& formatter, const sink_config_t& sink) {
    if (sink.type == "files") {
        typedef sink::file_t<> sink_type;

        std::string path = sink.args.at("path");
        auto s = std::make_unique<sink_type>(path);

        return create<Level>(formatter, std::move(s));
    } else if (sink.type == "syslog") {
        typedef sink::syslog_t<Level> sink_type;

        std::string identity = sink.args.at("identity");
        auto s = std::make_unique<sink_type>(identity);

        return create<Level>(formatter, std::move(s));
    } else if (sink.type == "socket") {
        std::string type = sink.args.at("type");
        if (type == "udp") {
            typedef sink::socket_t<boost::asio::ip::udp> sink_type;
            std::string host = sink.args.at("host");
            std::uint16_t port = boost::lexical_cast<std::uint16_t>(sink.args.at("port"));
            auto s = std::make_unique<sink_type>(host, port);

            return create<Level>(formatter, std::move(s));
        } else if (type == "tcp") {
            typedef sink::socket_t<boost::asio::ip::tcp> sink_type;
            std::string host = sink.args.at("host");
            std::uint16_t port = boost::lexical_cast<std::uint16_t>(sink.args.at("port"));
            auto s = std::make_unique<sink_type>(host, port);

            return create<Level>(formatter, std::move(s));
        }
    }

    return std::unique_ptr<base_frontend_t>();
}

} // namespace factory

} // namespace blackhole

TEST(Factory, FileStringsFrontend) {
    formatter_config_t formatter = {
        "string",
        { { "pattern", "[%(timestamp)s]: %(message)s" } }
    };

    sink_config_t sink = {
        "files",
        { { "path", "/dev/stdout" } }
    };

    EXPECT_TRUE(bool(factory::create<testing::level>(formatter, sink)));
}

TEST(Factory, SyslogStringsFrontend) {
    formatter_config_t formatter = {
        "string",
        { { "pattern", "[%(timestamp)s]: %(message)s" } }
    };

    sink_config_t sink = {
        "syslog",
        { { "identity", "AppIdentity" } }
    };

    EXPECT_TRUE(bool(factory::create<testing::level>(formatter, sink)));
}

TEST(Factory, UdpSocketStringsFrontend) {
    formatter_config_t formatter = {
        "string",
        { { "pattern", "[%(timestamp)s]: %(message)s" } }
    };

    sink_config_t sink = {
        "socket", {
            { "type", "udp" },
            { "host", "localhost" },
            { "port", "50030" }
        }
    };

    EXPECT_TRUE(bool(factory::create<testing::level>(formatter, sink)));
}

TEST(Factory, TcpSocketStringsFrontend) {
    formatter_config_t formatter = {
        "string",
        { { "pattern", "[%(timestamp)s]: %(message)s" } }
    };

    sink_config_t sink = {
        "socket", {
            { "type", "tcp" },
            { "host", "localhost" },
            { "port", "50030" }
        }
    };

    EXPECT_TRUE(bool(factory::create<testing::level>(formatter, sink)));
}
<commit_msg>Code style.<commit_after>#include "Mocks.hpp"

namespace testing {

enum class level : std::uint8_t { debug, info, warn, error };

} // namespace testing

namespace blackhole { namespace sink {

template<>
struct priority_traits<testing::level> {
    static inline
    priority_t map(testing::level lvl) {
        switch (lvl) {
        case testing::level::debug:
            return priority_t::debug;
        case testing::level::info:
            return priority_t::info;
        case testing::level::warn:
            return priority_t::warning;
        case testing::level::error:
            return priority_t::err;
        }
    }
};

} } // namespace blackhole::sink

namespace blackhole {

struct formatter_config_t {
    std::string type;
    std::map<std::string, std::string> args;
};

struct sink_config_t {
    std::string type;
    std::map<std::string, std::string> args;
};

namespace factory {

template<typename Level, typename Sink>
std::unique_ptr<base_frontend_t>
create(const formatter_config_t& formatter_config, std::unique_ptr<Sink> sink) {
    if (formatter_config.type == "string") {
        typedef formatter::string_t formatter_type;

        std::string pattern = formatter_config.args.at("pattern");
        auto formatter = std::make_unique<formatter_type>(pattern);

        return std::make_unique<frontend_t<formatter_type, Sink, Level>>(std::move(formatter), std::move(sink));
    }

    return std::unique_ptr<base_frontend_t>();
}

template<typename Level>
std::unique_ptr<base_frontend_t>
create(const formatter_config_t& formatter_config, const sink_config_t& sink_config) {
    if (sink_config.type == "files") {
        std::string path = sink_config.args.at("path");
        auto sink = std::make_unique<sink::file_t<>>(path);
        return create<Level>(formatter_config, std::move(sink));
    } else if (sink_config.type == "syslog") {
        std::string identity = sink_config.args.at("identity");
        auto sink = std::make_unique<sink::syslog_t<Level>>(identity);
        return create<Level>(formatter_config, std::move(sink));
    } else if (sink_config.type == "socket") {
        std::string type = sink_config.args.at("type");
        if (type == "udp") {
            std::string host = sink_config.args.at("host");
            std::uint16_t port = boost::lexical_cast<std::uint16_t>(sink_config.args.at("port"));
            auto sink = std::make_unique<sink::socket_t<boost::asio::ip::udp>>(host, port);
            return create<Level>(formatter_config, std::move(sink));
        } else if (type == "tcp") {
            std::string host = sink_config.args.at("host");
            std::uint16_t port = boost::lexical_cast<std::uint16_t>(sink_config.args.at("port"));
            auto sink = std::make_unique<sink::socket_t<boost::asio::ip::tcp>>(host, port);
            return create<Level>(formatter_config, std::move(sink));
        }
    }

    return std::unique_ptr<base_frontend_t>();
}

} // namespace factory

} // namespace blackhole

TEST(Factory, FileStringsFrontend) {
    formatter_config_t formatter = {
        "string",
        { { "pattern", "[%(timestamp)s]: %(message)s" } }
    };

    sink_config_t sink = {
        "files",
        { { "path", "/dev/stdout" } }
    };

    EXPECT_TRUE(bool(factory::create<testing::level>(formatter, sink)));
}

TEST(Factory, SyslogStringsFrontend) {
    formatter_config_t formatter = {
        "string",
        { { "pattern", "[%(timestamp)s]: %(message)s" } }
    };

    sink_config_t sink = {
        "syslog",
        { { "identity", "AppIdentity" } }
    };

    EXPECT_TRUE(bool(factory::create<testing::level>(formatter, sink)));
}

TEST(Factory, UdpSocketStringsFrontend) {
    formatter_config_t formatter = {
        "string",
        { { "pattern", "[%(timestamp)s]: %(message)s" } }
    };

    sink_config_t sink = {
        "socket", {
            { "type", "udp" },
            { "host", "localhost" },
            { "port", "50030" }
        }
    };

    EXPECT_TRUE(bool(factory::create<testing::level>(formatter, sink)));
}

TEST(Factory, TcpSocketStringsFrontend) {
    formatter_config_t formatter = {
        "string",
        { { "pattern", "[%(timestamp)s]: %(message)s" } }
    };

    sink_config_t sink = {
        "socket", {
            { "type", "tcp" },
            { "host", "localhost" },
            { "port", "50030" }
        }
    };

    EXPECT_TRUE(bool(factory::create<testing::level>(formatter, sink)));
}
<|endoftext|>


<commit_before>// Copyright (c) 2009-2012 Bitcoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <iostream>
#include <fstream>

#include "init.h" // for pwalletMain
#include "rpcserver.h"
#include "rpcprotocol.h"
#include "ui_interface.h"
#include "base58.h"

#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/variant/get.hpp>
#include <boost/algorithm/string.hpp>

using namespace std;

void EnsureWalletIsUnlocked();

namespace bt = boost::posix_time;

// Extended DecodeDumpTime implementation, see this page for details:
// http://stackoverflow.com/questions/3786201/parsing-of-date-time-from-string-boost
const std::locale formats[] = {
    std::locale(std::locale::classic(),new bt::time_input_facet("%Y-%m-%dT%H:%M:%SZ")),
    std::locale(std::locale::classic(),new bt::time_input_facet("%Y-%m-%d %H:%M:%S")),
    std::locale(std::locale::classic(),new bt::time_input_facet("%Y/%m/%d %H:%M:%S")),
    std::locale(std::locale::classic(),new bt::time_input_facet("%d.%m.%Y %H:%M:%S")),
    std::locale(std::locale::classic(),new bt::time_input_facet("%Y-%m-%d"))
};

const size_t formats_n = sizeof(formats)/sizeof(formats[0]);

std::time_t pt_to_time_t(const bt::ptime& pt)
{
    bt::ptime timet_start(boost::gregorian::date(1970,1,1));
    bt::time_duration diff = pt - timet_start;
    return diff.ticks()/bt::time_duration::rep_type::ticks_per_second;
}

int64_t DecodeDumpTime(const std::string& s)
{
    bt::ptime pt;

    for(size_t i=0; i<formats_n; ++i)
    {
        std::istringstream is(s);
        is.imbue(formats[i]);
        is >> pt;
        if(pt != bt::ptime()) break;
    }

    return pt_to_time_t(pt);
}

std::string static EncodeDumpTime(int64_t nTime) {
    return DateTimeStrFormat("%Y-%m-%dT%H:%M:%SZ", nTime);
}

std::string static EncodeDumpString(const std::string &str) {
    std::stringstream ret;
    for (unsigned char c : str) {
        if (c <= 32 || c >= 128 || c == '%') {
            ret << '%' << HexStr(&c, &c + 1);
        } else {
            ret << c;
        }
    }
    return ret.str();
}

std::string DecodeDumpString(const std::string &str) {
    std::stringstream ret;
    for (unsigned int pos = 0; pos < str.length(); pos++) {
        unsigned char c = str[pos];
        if (c == '%' && pos+2 < str.length()) {
            c = (((str[pos+1]>>6)*9+((str[pos+1]-'0')&15)) << 4) |
                ((str[pos+2]>>6)*9+((str[pos+2]-'0')&15));
            pos += 2;
        }
        ret << c;
    }
    return ret.str();
}

class CTxDump
{
public:
    CBlockIndex *pindex;
    int64_t nValue;
    bool fSpent;
    CWalletTx* ptx;
    int nOut;
    CTxDump(CWalletTx* ptx = NULL, int nOut = -1)
    {
        pindex = NULL;
        nValue = 0;
        fSpent = false;
        this->ptx = ptx;
        this->nOut = nOut;
    }
};

UniValue importprivkey(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 3)
        throw runtime_error(
        "importprivkey <gridcoinprivkey> [label] [bool:rescan]\n"
        "\n"
        "[label] -------> Optional; Label for imported address\n"
        "[bool:rescan] -> Optional; Default true\n"
        "\n"
        "Adds a private key (as returned by dumpprivkey) to your wallet\n");

    string strSecret = params[0].get_str();
    string strLabel = "";
    if (params.size() > 1)
        strLabel = params[1].get_str();

     // Whether to perform rescan after import
    bool fRescan = true;
    if (params.size() > 2)
        fRescan = params[2].get_bool();

    CBitcoinSecret vchSecret;
    CKey key;
    bool fGood = vchSecret.SetString(strSecret);

    // If CBitcoinSecret key decode failed, try to decode the key as hex
    if(!fGood)
    {
        auto vecsecret = ParseHex(strSecret);
        if(!key.SetPrivKey(CPrivKey(vecsecret.begin(),vecsecret.end())))
            throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
    }
    else
    {
    bool fCompressed;
    CSecret secret = vchSecret.GetSecret(fCompressed);
    key.SetSecret(secret, fCompressed);
    }

    if (fWalletUnlockStakingOnly)
        throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Wallet is unlocked for staking only.");

    CKeyID vchAddress = key.GetPubKey().GetID();
    {
        LOCK2(cs_main, pwalletMain->cs_wallet);

        pwalletMain->MarkDirty();

        // Don't throw error in case a key is already there
        if (pwalletMain->HaveKey(vchAddress))
            return NullUniValue;

        pwalletMain->mapKeyMetadata[vchAddress].nCreateTime = 1;

        if (!pwalletMain->AddKey(key))
            throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");

        // whenever a key is imported, we need to scan the whole chain
        pwalletMain->nTimeFirstKey = 1; // 0 would be considered 'no value'
        pwalletMain->SetAddressBookName(vchAddress, strLabel);

        if (fRescan)
        {
            pwalletMain->ScanForWalletTransactions(pindexGenesisBlock, true);
            pwalletMain->ReacceptWalletTransactions();
        }
    }

    return NullUniValue;
}

UniValue importwallet(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() != 1)
        throw runtime_error(
            "importwallet <filename>\n"
            "\n"
            "<filename> -> filename of the wallet to import\n"
            "\n"
            "Imports keys from a wallet dump file (see dumpwallet)\n");

    ifstream file;
    file.open(params[0].get_str().c_str());
    if (!file.is_open())
        throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");

    LOCK2(cs_main, pwalletMain->cs_wallet);

    EnsureWalletIsUnlocked();

    int64_t nTimeBegin = pindexBest->nTime;

    bool fGood = true;

    while (file.good()) {
        std::string line;
        std::getline(file, line);
        if (line.empty() || line[0] == '#')
            continue;

        std::vector<std::string> vstr;
        boost::split(vstr, line, boost::is_any_of(" "));
        if (vstr.size() < 2)
            continue;
        CBitcoinSecret vchSecret;
        if (!vchSecret.SetString(vstr[0]))
            continue;

        bool fCompressed;
        CKey key;
        CSecret secret = vchSecret.GetSecret(fCompressed);
        key.SetSecret(secret, fCompressed);
        CKeyID keyid = key.GetPubKey().GetID();

        if (pwalletMain->HaveKey(keyid)) {
            LogPrintf("Skipping import of %s (key already present)", CBitcoinAddress(keyid).ToString());
            continue;
        }
        int64_t nTime = DecodeDumpTime(vstr[1]);
        std::string strLabel;
        bool fLabel = true;
        for (unsigned int nStr = 2; nStr < vstr.size(); nStr++) {
            if (boost::algorithm::starts_with(vstr[nStr], "#"))
                break;
            if (vstr[nStr] == "change=1")
                fLabel = false;
            if (vstr[nStr] == "reserve=1")
                fLabel = false;
            if (boost::algorithm::starts_with(vstr[nStr], "label=")) {
                strLabel = DecodeDumpString(vstr[nStr].substr(6));
                fLabel = true;
            }
        }
        LogPrintf("Importing %s...", CBitcoinAddress(keyid).ToString());
        if (!pwalletMain->AddKey(key)) {
            fGood = false;
            continue;
        }
        pwalletMain->mapKeyMetadata[keyid].nCreateTime = nTime;
        if (fLabel)
            pwalletMain->SetAddressBookName(keyid, strLabel);
        nTimeBegin = std::min(nTimeBegin, nTime);
    }
    file.close();

    CBlockIndex *pindex = pindexBest;
    while (pindex && pindex->pprev && pindex->nTime > nTimeBegin - 7200)
        pindex = pindex->pprev;

    if (!pwalletMain->nTimeFirstKey || nTimeBegin < pwalletMain->nTimeFirstKey)
        pwalletMain->nTimeFirstKey = nTimeBegin;

    LogPrintf("Rescanning last %i blocks", pindexBest->nHeight - pindex->nHeight + 1);
    pwalletMain->ScanForWalletTransactions(pindex);
    pwalletMain->ReacceptWalletTransactions();
    pwalletMain->MarkDirty();

    if (!fGood)
        throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys to wallet");

    return NullUniValue;
}

UniValue dumpprivkey(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() != 1)
        throw runtime_error(
            "dumpprivkey <gridcoinaddress>\n"
            "<gridcoinaddress> -> Address of requested key\n"
            "\n"
            "Reveals the private key corresponding to <gridcoinaddress>\n");

    EnsureWalletIsUnlocked();

    string strAddress = params[0].get_str();
    CBitcoinAddress address;
    if (!address.SetString(strAddress))
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Gridcoin address");
    if (fWalletUnlockStakingOnly)
        throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Wallet is unlocked for staking only.");

    LOCK2(cs_main, pwalletMain->cs_wallet);

    CKeyID keyID;
    if (!address.GetKeyID(keyID))
        throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key");
    CSecret vchSecret;
    bool fCompressed;
    if (!pwalletMain->GetSecret(keyID, vchSecret, fCompressed))
        throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known");
    return CBitcoinSecret(vchSecret, fCompressed).ToString();
}

UniValue dumpwallet(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() != 1)
        throw runtime_error(
            "dumpwallet <filename>\n"
            "\n"
            "<filename> -> filename to dump wallet to\n"
            "\n"
            "Dumps all wallet keys in a human-readable format\n");

    EnsureWalletIsUnlocked();

    ofstream file;
    file.open(params[0].get_str().c_str());
    if (!file.is_open())
        throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");

    std::map<CKeyID, int64_t> mapKeyBirth;

    std::set<CKeyID> setKeyPool;

    LOCK2(cs_main, pwalletMain->cs_wallet);

    pwalletMain->GetKeyBirthTimes(mapKeyBirth);

    pwalletMain->GetAllReserveKeys(setKeyPool);

    // sort time/key pairs
    std::vector<std::pair<int64_t, CKeyID> > vKeyBirth;
    for (std::map<CKeyID, int64_t>::const_iterator it = mapKeyBirth.begin(); it != mapKeyBirth.end(); it++) {
        vKeyBirth.push_back(std::make_pair(it->second, it->first));
    }
    mapKeyBirth.clear();
    std::sort(vKeyBirth.begin(), vKeyBirth.end());

    // produce output
    file << strprintf("# Wallet dump created by Gridcoin %s (%s)\n", CLIENT_BUILD, CLIENT_DATE);
    file << strprintf("# * Created on %s\n", EncodeDumpTime(GetTime()));
    file << strprintf("# * Best block at time of backup was %i (%s),\n", nBestHeight, hashBestChain.ToString());
    file << strprintf("#   mined on %s\n", EncodeDumpTime(pindexBest->nTime));
    file << "\n";
    for (std::vector<std::pair<int64_t, CKeyID> >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) {
        const CKeyID &keyid = it->second;
        std::string strTime = EncodeDumpTime(it->first);
        std::string strAddr = CBitcoinAddress(keyid).ToString();
        bool IsCompressed;

        CKey key;
        if (pwalletMain->GetKey(keyid, key)) {
            if (pwalletMain->mapAddressBook.count(keyid)) {
                CSecret secret = key.GetSecret(IsCompressed);
                file << strprintf("%s %s label=%s # addr=%s\n", CBitcoinSecret(secret, IsCompressed).ToString(), strTime, EncodeDumpString(pwalletMain->mapAddressBook[keyid]), strAddr);
            } else if (setKeyPool.count(keyid)) {
                CSecret secret = key.GetSecret(IsCompressed);
                file << strprintf("%s %s reserve=1 # addr=%s\n", CBitcoinSecret(secret, IsCompressed).ToString(), strTime, strAddr);
            } else {
                CSecret secret = key.GetSecret(IsCompressed);
                file << strprintf("%s %s change=1 # addr=%s\n", CBitcoinSecret(secret, IsCompressed).ToString(), strTime, strAddr);
            }
        }
    }
    file << "\n";
    file << "# End of dump\n";
    file.close();
    return NullUniValue;
}
<commit_msg>Change dumpwallet to use appropriate data directory<commit_after>// Copyright (c) 2009-2012 Bitcoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <iostream>
#include <fstream>

#include "init.h" // for pwalletMain
#include "rpcserver.h"
#include "rpcprotocol.h"
#include "ui_interface.h"
#include "base58.h"

#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/variant/get.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>

using namespace std;

void EnsureWalletIsUnlocked();

namespace bt = boost::posix_time;

// Extended DecodeDumpTime implementation, see this page for details:
// http://stackoverflow.com/questions/3786201/parsing-of-date-time-from-string-boost
const std::locale formats[] = {
    std::locale(std::locale::classic(),new bt::time_input_facet("%Y-%m-%dT%H:%M:%SZ")),
    std::locale(std::locale::classic(),new bt::time_input_facet("%Y-%m-%d %H:%M:%S")),
    std::locale(std::locale::classic(),new bt::time_input_facet("%Y/%m/%d %H:%M:%S")),
    std::locale(std::locale::classic(),new bt::time_input_facet("%d.%m.%Y %H:%M:%S")),
    std::locale(std::locale::classic(),new bt::time_input_facet("%Y-%m-%d"))
};

const size_t formats_n = sizeof(formats)/sizeof(formats[0]);

std::time_t pt_to_time_t(const bt::ptime& pt)
{
    bt::ptime timet_start(boost::gregorian::date(1970,1,1));
    bt::time_duration diff = pt - timet_start;
    return diff.ticks()/bt::time_duration::rep_type::ticks_per_second;
}

int64_t DecodeDumpTime(const std::string& s)
{
    bt::ptime pt;

    for(size_t i=0; i<formats_n; ++i)
    {
        std::istringstream is(s);
        is.imbue(formats[i]);
        is >> pt;
        if(pt != bt::ptime()) break;
    }

    return pt_to_time_t(pt);
}

std::string static EncodeDumpTime(int64_t nTime) {
    return DateTimeStrFormat("%Y-%m-%dT%H:%M:%SZ", nTime);
}

std::string static EncodeDumpString(const std::string &str) {
    std::stringstream ret;
    for (unsigned char c : str) {
        if (c <= 32 || c >= 128 || c == '%') {
            ret << '%' << HexStr(&c, &c + 1);
        } else {
            ret << c;
        }
    }
    return ret.str();
}

std::string DecodeDumpString(const std::string &str) {
    std::stringstream ret;
    for (unsigned int pos = 0; pos < str.length(); pos++) {
        unsigned char c = str[pos];
        if (c == '%' && pos+2 < str.length()) {
            c = (((str[pos+1]>>6)*9+((str[pos+1]-'0')&15)) << 4) |
                ((str[pos+2]>>6)*9+((str[pos+2]-'0')&15));
            pos += 2;
        }
        ret << c;
    }
    return ret.str();
}

class CTxDump
{
public:
    CBlockIndex *pindex;
    int64_t nValue;
    bool fSpent;
    CWalletTx* ptx;
    int nOut;
    CTxDump(CWalletTx* ptx = NULL, int nOut = -1)
    {
        pindex = NULL;
        nValue = 0;
        fSpent = false;
        this->ptx = ptx;
        this->nOut = nOut;
    }
};

UniValue importprivkey(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 3)
        throw runtime_error(
        "importprivkey <gridcoinprivkey> [label] [bool:rescan]\n"
        "\n"
        "[label] -------> Optional; Label for imported address\n"
        "[bool:rescan] -> Optional; Default true\n"
        "\n"
        "Adds a private key (as returned by dumpprivkey) to your wallet\n");

    string strSecret = params[0].get_str();
    string strLabel = "";
    if (params.size() > 1)
        strLabel = params[1].get_str();

     // Whether to perform rescan after import
    bool fRescan = true;
    if (params.size() > 2)
        fRescan = params[2].get_bool();

    CBitcoinSecret vchSecret;
    CKey key;
    bool fGood = vchSecret.SetString(strSecret);

    // If CBitcoinSecret key decode failed, try to decode the key as hex
    if(!fGood)
    {
        auto vecsecret = ParseHex(strSecret);
        if(!key.SetPrivKey(CPrivKey(vecsecret.begin(),vecsecret.end())))
            throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
    }
    else
    {
    bool fCompressed;
    CSecret secret = vchSecret.GetSecret(fCompressed);
    key.SetSecret(secret, fCompressed);
    }

    if (fWalletUnlockStakingOnly)
        throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Wallet is unlocked for staking only.");

    CKeyID vchAddress = key.GetPubKey().GetID();
    {
        LOCK2(cs_main, pwalletMain->cs_wallet);

        pwalletMain->MarkDirty();

        // Don't throw error in case a key is already there
        if (pwalletMain->HaveKey(vchAddress))
            return NullUniValue;

        pwalletMain->mapKeyMetadata[vchAddress].nCreateTime = 1;

        if (!pwalletMain->AddKey(key))
            throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");

        // whenever a key is imported, we need to scan the whole chain
        pwalletMain->nTimeFirstKey = 1; // 0 would be considered 'no value'
        pwalletMain->SetAddressBookName(vchAddress, strLabel);

        if (fRescan)
        {
            pwalletMain->ScanForWalletTransactions(pindexGenesisBlock, true);
            pwalletMain->ReacceptWalletTransactions();
        }
    }

    return NullUniValue;
}

UniValue importwallet(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() != 1)
        throw runtime_error(
            "importwallet <filename>\n"
            "\n"
            "<filename> -> filename of the wallet to import\n"
            "\n"
            "Imports keys from a wallet dump file (see dumpwallet)\n");

    ifstream file;
    file.open(params[0].get_str().c_str());
    if (!file.is_open())
        throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");

    LOCK2(cs_main, pwalletMain->cs_wallet);

    EnsureWalletIsUnlocked();

    int64_t nTimeBegin = pindexBest->nTime;

    bool fGood = true;

    while (file.good()) {
        std::string line;
        std::getline(file, line);
        if (line.empty() || line[0] == '#')
            continue;

        std::vector<std::string> vstr;
        boost::split(vstr, line, boost::is_any_of(" "));
        if (vstr.size() < 2)
            continue;
        CBitcoinSecret vchSecret;
        if (!vchSecret.SetString(vstr[0]))
            continue;

        bool fCompressed;
        CKey key;
        CSecret secret = vchSecret.GetSecret(fCompressed);
        key.SetSecret(secret, fCompressed);
        CKeyID keyid = key.GetPubKey().GetID();

        if (pwalletMain->HaveKey(keyid)) {
            LogPrintf("Skipping import of %s (key already present)", CBitcoinAddress(keyid).ToString());
            continue;
        }
        int64_t nTime = DecodeDumpTime(vstr[1]);
        std::string strLabel;
        bool fLabel = true;
        for (unsigned int nStr = 2; nStr < vstr.size(); nStr++) {
            if (boost::algorithm::starts_with(vstr[nStr], "#"))
                break;
            if (vstr[nStr] == "change=1")
                fLabel = false;
            if (vstr[nStr] == "reserve=1")
                fLabel = false;
            if (boost::algorithm::starts_with(vstr[nStr], "label=")) {
                strLabel = DecodeDumpString(vstr[nStr].substr(6));
                fLabel = true;
            }
        }
        LogPrintf("Importing %s...", CBitcoinAddress(keyid).ToString());
        if (!pwalletMain->AddKey(key)) {
            fGood = false;
            continue;
        }
        pwalletMain->mapKeyMetadata[keyid].nCreateTime = nTime;
        if (fLabel)
            pwalletMain->SetAddressBookName(keyid, strLabel);
        nTimeBegin = std::min(nTimeBegin, nTime);
    }
    file.close();

    CBlockIndex *pindex = pindexBest;
    while (pindex && pindex->pprev && pindex->nTime > nTimeBegin - 7200)
        pindex = pindex->pprev;

    if (!pwalletMain->nTimeFirstKey || nTimeBegin < pwalletMain->nTimeFirstKey)
        pwalletMain->nTimeFirstKey = nTimeBegin;

    LogPrintf("Rescanning last %i blocks", pindexBest->nHeight - pindex->nHeight + 1);
    pwalletMain->ScanForWalletTransactions(pindex);
    pwalletMain->ReacceptWalletTransactions();
    pwalletMain->MarkDirty();

    if (!fGood)
        throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys to wallet");

    return NullUniValue;
}

UniValue dumpprivkey(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() != 1)
        throw runtime_error(
            "dumpprivkey <gridcoinaddress>\n"
            "<gridcoinaddress> -> Address of requested key\n"
            "\n"
            "Reveals the private key corresponding to <gridcoinaddress>\n");

    EnsureWalletIsUnlocked();

    string strAddress = params[0].get_str();
    CBitcoinAddress address;
    if (!address.SetString(strAddress))
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Gridcoin address");
    if (fWalletUnlockStakingOnly)
        throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Wallet is unlocked for staking only.");

    LOCK2(cs_main, pwalletMain->cs_wallet);

    CKeyID keyID;
    if (!address.GetKeyID(keyID))
        throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key");
    CSecret vchSecret;
    bool fCompressed;
    if (!pwalletMain->GetSecret(keyID, vchSecret, fCompressed))
        throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known");
    return CBitcoinSecret(vchSecret, fCompressed).ToString();
}

UniValue dumpwallet(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() != 1)
        throw runtime_error(
            "dumpwallet <filename>\n"
            "\n"
            "<filename> -> filename to dump wallet to\n"
            "\n"
            "Dumps all wallet keys in a human-readable format into the specified file.\n"
            "If a path is not specified in the filename, the data directory is used.");

    EnsureWalletIsUnlocked();

    boost::filesystem::path PathForDump = boost::filesystem::path(params[0].get_str());
    boost::filesystem::path DefaultPathDataDir = GetDataDir();

    // If provided filename does not have a path, then append parent path, otherwise leave alone.
    if (PathForDump.parent_path().empty())
        PathForDump = DefaultPathDataDir / PathForDump;

    ofstream file;
    file.open(PathForDump.string().c_str());
    if (!file.is_open())
        throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");

    std::map<CKeyID, int64_t> mapKeyBirth;

    std::set<CKeyID> setKeyPool;

    LOCK2(cs_main, pwalletMain->cs_wallet);

    pwalletMain->GetKeyBirthTimes(mapKeyBirth);

    pwalletMain->GetAllReserveKeys(setKeyPool);

    // sort time/key pairs
    std::vector<std::pair<int64_t, CKeyID> > vKeyBirth;
    for (std::map<CKeyID, int64_t>::const_iterator it = mapKeyBirth.begin(); it != mapKeyBirth.end(); it++) {
        vKeyBirth.push_back(std::make_pair(it->second, it->first));
    }
    mapKeyBirth.clear();
    std::sort(vKeyBirth.begin(), vKeyBirth.end());

    // produce output
    file << strprintf("# Wallet dump created by Gridcoin %s (%s)\n", CLIENT_BUILD, CLIENT_DATE);
    file << strprintf("# * Created on %s\n", EncodeDumpTime(GetTime()));
    file << strprintf("# * Best block at time of backup was %i (%s),\n", nBestHeight, hashBestChain.ToString());
    file << strprintf("#   mined on %s\n", EncodeDumpTime(pindexBest->nTime));
    file << "\n";
    for (std::vector<std::pair<int64_t, CKeyID> >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) {
        const CKeyID &keyid = it->second;
        std::string strTime = EncodeDumpTime(it->first);
        std::string strAddr = CBitcoinAddress(keyid).ToString();
        bool IsCompressed;

        CKey key;
        if (pwalletMain->GetKey(keyid, key)) {
            if (pwalletMain->mapAddressBook.count(keyid)) {
                CSecret secret = key.GetSecret(IsCompressed);
                file << strprintf("%s %s label=%s # addr=%s\n", CBitcoinSecret(secret, IsCompressed).ToString(), strTime, EncodeDumpString(pwalletMain->mapAddressBook[keyid]), strAddr);
            } else if (setKeyPool.count(keyid)) {
                CSecret secret = key.GetSecret(IsCompressed);
                file << strprintf("%s %s reserve=1 # addr=%s\n", CBitcoinSecret(secret, IsCompressed).ToString(), strTime, strAddr);
            } else {
                CSecret secret = key.GetSecret(IsCompressed);
                file << strprintf("%s %s change=1 # addr=%s\n", CBitcoinSecret(secret, IsCompressed).ToString(), strTime, strAddr);
            }
        }
    }
    file << "\n";
    file << "# End of dump\n";
    file.close();
    return NullUniValue;
}
<|endoftext|>


<commit_before>// Copyright (c) 2018-2019 The Dash Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <llmq/quorums.h>
#include <llmq/quorums_utils.h>

#include <chainparams.h>
#include <random.h>
#include <validation.h>

namespace llmq
{

std::vector<CDeterministicMNCPtr> CLLMQUtils::GetAllQuorumMembers(Consensus::LLMQType llmqType, const CBlockIndex* pindexQuorum)
{
    auto& params = Params().GetConsensus().llmqs.at(llmqType);
    auto allMns = deterministicMNManager->GetListForBlock(pindexQuorum);
    auto modifier = ::SerializeHash(std::make_pair(llmqType, pindexQuorum->GetBlockHash()));
    return allMns.CalculateQuorum(params.size, modifier);
}

uint256 CLLMQUtils::BuildCommitmentHash(Consensus::LLMQType llmqType, const uint256& blockHash, const std::vector<bool>& validMembers, const CBLSPublicKey& pubKey, const uint256& vvecHash)
{
    CHashWriter hw(SER_NETWORK, 0);
    hw << llmqType;
    hw << blockHash;
    hw << DYNBITSET(validMembers);
    hw << pubKey;
    hw << vvecHash;
    return hw.GetHash();
}

uint256 CLLMQUtils::BuildSignHash(Consensus::LLMQType llmqType, const uint256& quorumHash, const uint256& id, const uint256& msgHash)
{
    CHashWriter h(SER_GETHASH, 0);
    h << llmqType;
    h << quorumHash;
    h << id;
    h << msgHash;
    return h.GetHash();
}

std::set<uint256> CLLMQUtils::GetQuorumConnections(Consensus::LLMQType llmqType, const CBlockIndex* pindexQuorum, const uint256& forMember)
{
    auto& params = Params().GetConsensus().llmqs.at(llmqType);

    auto mns = GetAllQuorumMembers(llmqType, pindexQuorum);
    std::set<uint256> result;
    for (size_t i = 0; i < mns.size(); i++) {
        auto& dmn = mns[i];
        if (dmn->proTxHash == forMember) {
            // Connect to nodes at indexes (i+2^k)%n, where
            //   k: 0..max(1, floor(log2(n-1))-1)
            //   n: size of the quorum/ring
            int gap = 1;
            int gap_max = (int)mns.size() - 1;
            int k = 0;
            while ((gap_max >>= 1) || k <= 1) {
                size_t idx = (i + gap) % mns.size();
                auto& otherDmn = mns[idx];
                if (otherDmn == dmn) {
                    continue;
                }
                result.emplace(otherDmn->proTxHash);
                gap <<= 1;
                k++;
            }
            // there can be no two members with the same proTxHash, so return early
            break;
        }
    }
    return result;
}

std::set<size_t> CLLMQUtils::CalcDeterministicWatchConnections(Consensus::LLMQType llmqType, const CBlockIndex* pindexQuorum, size_t memberCount, size_t connectionCount)
{
    static uint256 qwatchConnectionSeed;
    static std::atomic<bool> qwatchConnectionSeedGenerated{false};
    static CCriticalSection qwatchConnectionSeedCs;
    if (!qwatchConnectionSeedGenerated) {
        LOCK(qwatchConnectionSeedCs);
        if (!qwatchConnectionSeedGenerated) {
            qwatchConnectionSeed = GetRandHash();
            qwatchConnectionSeedGenerated = true;
        }
    }

    std::set<size_t> result;
    uint256 rnd = qwatchConnectionSeed;
    for (size_t i = 0; i < connectionCount; i++) {
        rnd = ::SerializeHash(std::make_pair(rnd, std::make_pair(llmqType, pindexQuorum->GetBlockHash())));
        result.emplace(rnd.GetUint64(0) % memberCount);
    }
    return result;
}

void CLLMQUtils::EnsureQuorumConnections(Consensus::LLMQType llmqType, const CBlockIndex *pindexQuorum, const uint256& myProTxHash, bool allowWatch)
{
    auto members = GetAllQuorumMembers(llmqType, pindexQuorum);
    bool isMember = std::find_if(members.begin(), members.end(), [&](const CDeterministicMNCPtr& dmn) { return dmn->proTxHash == myProTxHash; }) != members.end();

    if (!isMember && !allowWatch) {
        return;
    }

    std::set<uint256> connections;
    if (isMember) {
        connections = CLLMQUtils::GetQuorumConnections(llmqType, pindexQuorum, myProTxHash);
    } else {
        auto cindexes = CLLMQUtils::CalcDeterministicWatchConnections(llmqType, pindexQuorum, members.size(), 1);
        for (auto idx : cindexes) {
            connections.emplace(members[idx]->proTxHash);
        }
    }
    if (!connections.empty()) {
        if (!g_connman->HasMasternodeQuorumNodes(llmqType, pindexQuorum->GetBlockHash()) && LogAcceptCategory(BCLog::LLMQ)) {
            auto mnList = deterministicMNManager->GetListAtChainTip();
            std::string debugMsg = strprintf("CLLMQUtils::%s -- adding masternodes quorum connections for quorum %s:\n", __func__, pindexQuorum->GetBlockHash().ToString());
            for (auto& c : connections) {
                auto dmn = mnList.GetValidMN(c);
                if (!dmn) {
                    debugMsg += strprintf("  %s (not in valid MN set anymore)\n", c.ToString());
                } else {
                    debugMsg += strprintf("  %s (%s)\n", c.ToString(), dmn->pdmnState->addr.ToString(false));
                }
            }
            LogPrint(BCLog::LLMQ, debugMsg.c_str());
        }
        g_connman->SetMasternodeQuorumNodes(llmqType, pindexQuorum->GetBlockHash(), connections);
    }
}

bool CLLMQUtils::IsQuorumActive(Consensus::LLMQType llmqType, const uint256& quorumHash)
{
    auto& params = Params().GetConsensus().llmqs.at(llmqType);

    // sig shares and recovered sigs are only accepted from recent/active quorums
    // we allow one more active quorum as specified in consensus, as otherwise there is a small window where things could
    // fail while we are on the brink of a new quorum
    auto quorums = quorumManager->ScanQuorums(llmqType, (int)params.signingActiveQuorumCount + 1);
    for (auto& q : quorums) {
        if (q->qc.quorumHash == quorumHash) {
            return true;
        }
    }
    return false;
}

} // namespace llmq
<commit_msg>Connect all LLMQ members to all other members<commit_after>// Copyright (c) 2018-2019 The Dash Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <llmq/quorums.h>
#include <llmq/quorums_utils.h>

#include <chainparams.h>
#include <random.h>
#include <spork.h>
#include <validation.h>

namespace llmq
{

std::vector<CDeterministicMNCPtr> CLLMQUtils::GetAllQuorumMembers(Consensus::LLMQType llmqType, const CBlockIndex* pindexQuorum)
{
    auto& params = Params().GetConsensus().llmqs.at(llmqType);
    auto allMns = deterministicMNManager->GetListForBlock(pindexQuorum);
    auto modifier = ::SerializeHash(std::make_pair(llmqType, pindexQuorum->GetBlockHash()));
    return allMns.CalculateQuorum(params.size, modifier);
}

uint256 CLLMQUtils::BuildCommitmentHash(Consensus::LLMQType llmqType, const uint256& blockHash, const std::vector<bool>& validMembers, const CBLSPublicKey& pubKey, const uint256& vvecHash)
{
    CHashWriter hw(SER_NETWORK, 0);
    hw << llmqType;
    hw << blockHash;
    hw << DYNBITSET(validMembers);
    hw << pubKey;
    hw << vvecHash;
    return hw.GetHash();
}

uint256 CLLMQUtils::BuildSignHash(Consensus::LLMQType llmqType, const uint256& quorumHash, const uint256& id, const uint256& msgHash)
{
    CHashWriter h(SER_GETHASH, 0);
    h << llmqType;
    h << quorumHash;
    h << id;
    h << msgHash;
    return h.GetHash();
}

std::set<uint256> CLLMQUtils::GetQuorumConnections(Consensus::LLMQType llmqType, const CBlockIndex* pindexQuorum, const uint256& forMember)
{
    auto& params = Params().GetConsensus().llmqs.at(llmqType);

    auto mns = GetAllQuorumMembers(llmqType, pindexQuorum);
    std::set<uint256> result;

    if (sporkManager.IsSporkActive(SPORK_21_QUORUM_ALL_CONNECTED)) {
        for (auto& dmn : mns) {
            // this will cause deterministic behaviour between incoming and outgoing connections.
            // Each member needs a connection to all other members, so we have each member paired. The below check
            // will be true on one side and false on the other side of the pairing, so we avoid having both members
            // initiating the connection.
            if (dmn->proTxHash < forMember) {
                result.emplace(dmn->proTxHash);
            }
        }
        return result;
    }

    // TODO remove this after activation of SPORK_21_QUORUM_ALL_CONNECTED

    for (size_t i = 0; i < mns.size(); i++) {
        auto& dmn = mns[i];
        if (dmn->proTxHash == forMember) {
            // Connect to nodes at indexes (i+2^k)%n, where
            //   k: 0..max(1, floor(log2(n-1))-1)
            //   n: size of the quorum/ring
            int gap = 1;
            int gap_max = (int)mns.size() - 1;
            int k = 0;
            while ((gap_max >>= 1) || k <= 1) {
                size_t idx = (i + gap) % mns.size();
                auto& otherDmn = mns[idx];
                if (otherDmn == dmn) {
                    continue;
                }
                result.emplace(otherDmn->proTxHash);
                gap <<= 1;
                k++;
            }
            // there can be no two members with the same proTxHash, so return early
            break;
        }
    }
    return result;
}

std::set<size_t> CLLMQUtils::CalcDeterministicWatchConnections(Consensus::LLMQType llmqType, const CBlockIndex* pindexQuorum, size_t memberCount, size_t connectionCount)
{
    static uint256 qwatchConnectionSeed;
    static std::atomic<bool> qwatchConnectionSeedGenerated{false};
    static CCriticalSection qwatchConnectionSeedCs;
    if (!qwatchConnectionSeedGenerated) {
        LOCK(qwatchConnectionSeedCs);
        if (!qwatchConnectionSeedGenerated) {
            qwatchConnectionSeed = GetRandHash();
            qwatchConnectionSeedGenerated = true;
        }
    }

    std::set<size_t> result;
    uint256 rnd = qwatchConnectionSeed;
    for (size_t i = 0; i < connectionCount; i++) {
        rnd = ::SerializeHash(std::make_pair(rnd, std::make_pair(llmqType, pindexQuorum->GetBlockHash())));
        result.emplace(rnd.GetUint64(0) % memberCount);
    }
    return result;
}

void CLLMQUtils::EnsureQuorumConnections(Consensus::LLMQType llmqType, const CBlockIndex *pindexQuorum, const uint256& myProTxHash, bool allowWatch)
{
    auto members = GetAllQuorumMembers(llmqType, pindexQuorum);
    bool isMember = std::find_if(members.begin(), members.end(), [&](const CDeterministicMNCPtr& dmn) { return dmn->proTxHash == myProTxHash; }) != members.end();

    if (!isMember && !allowWatch) {
        return;
    }

    std::set<uint256> connections;
    if (isMember) {
        connections = CLLMQUtils::GetQuorumConnections(llmqType, pindexQuorum, myProTxHash);
    } else {
        auto cindexes = CLLMQUtils::CalcDeterministicWatchConnections(llmqType, pindexQuorum, members.size(), 1);
        for (auto idx : cindexes) {
            connections.emplace(members[idx]->proTxHash);
        }
    }
    if (!connections.empty()) {
        if (!g_connman->HasMasternodeQuorumNodes(llmqType, pindexQuorum->GetBlockHash()) && LogAcceptCategory(BCLog::LLMQ)) {
            auto mnList = deterministicMNManager->GetListAtChainTip();
            std::string debugMsg = strprintf("CLLMQUtils::%s -- adding masternodes quorum connections for quorum %s:\n", __func__, pindexQuorum->GetBlockHash().ToString());
            for (auto& c : connections) {
                auto dmn = mnList.GetValidMN(c);
                if (!dmn) {
                    debugMsg += strprintf("  %s (not in valid MN set anymore)\n", c.ToString());
                } else {
                    debugMsg += strprintf("  %s (%s)\n", c.ToString(), dmn->pdmnState->addr.ToString(false));
                }
            }
            LogPrint(BCLog::LLMQ, debugMsg.c_str());
        }
        g_connman->SetMasternodeQuorumNodes(llmqType, pindexQuorum->GetBlockHash(), connections);
    }
}

bool CLLMQUtils::IsQuorumActive(Consensus::LLMQType llmqType, const uint256& quorumHash)
{
    auto& params = Params().GetConsensus().llmqs.at(llmqType);

    // sig shares and recovered sigs are only accepted from recent/active quorums
    // we allow one more active quorum as specified in consensus, as otherwise there is a small window where things could
    // fail while we are on the brink of a new quorum
    auto quorums = quorumManager->ScanQuorums(llmqType, (int)params.signingActiveQuorumCount + 1);
    for (auto& q : quorums) {
        if (q->qc.quorumHash == quorumHash) {
            return true;
        }
    }
    return false;
}

} // namespace llmq
<|endoftext|>