<commit_before>/*
 The MIT License (MIT)

 Copyright (C) 2017 RSK Labs Ltd.

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 */

/**
  File: GwMaker.cc
  Purpose: Poll RSK node to get new work and send it to Kafka "RawGw" topic

  @author Martin Medina
  @copyright RSK Labs Ltd.
  @version 1.0 30/03/17
*/

#include "GwMaker.h"

#include <glog/logging.h>
#include <util.h>
#include <utilstrencodings.h>
#include "Utils.h"

// GwMaker::GwMaker(const string &rskdRpcAddr, const string &rskdRpcUserpass,
//                    const string &kafkaBrokers, uint32_t kRpcCallInterval)
// : running_(true), rskdRpcAddr_(rskdRpcAddr),
// rskdRpcUserpass_(rskdRpcUserpass), kRpcCallInterval_(kRpcCallInterval),
// kafkaBrokers_(kafkaBrokers),
// kafkaProducer_(kafkaBrokers_.c_str(), KAFKA_TOPIC_RAWGW, 0/* partition */)
// {
// }

GwMaker::GwMaker(const GwDefinition gwDef) : gwDef_(gwDef),
                                             running_(true),
                                             kafkaProducer_(gwDef.broker.c_str(), gwDef.topic.c_str(), 0 /* partition */)
{
}

GwMaker::~GwMaker() {}

bool GwMaker::init() {
  map<string, string> options;
  // set to 1 (0 is an illegal value here), deliver msg as soon as possible.
  options["queue.buffering.max.ms"] = "1";
  if (!kafkaProducer_.setup(&options)) {
    LOG(ERROR) << "kafka producer setup failure";
    return false;
  }

  // setup kafka and check if it's alive
  if (!kafkaProducer_.checkAlive()) {
    LOG(ERROR) << "kafka is NOT alive";
    return false;
  }

  // TODO: check rskd is alive in a similar way as done for btcd

  return true;
}

void GwMaker::stop() {
  if (!running_) {
    return;
  }
  running_ = false;
  LOG(INFO) << "stop GwMaker";
}

void GwMaker::kafkaProduceMsg(const void *payload, size_t len) {
  kafkaProducer_.produce(payload, len);
}

// string GwMaker::constructRequest() {
//   //return "{\"jsonrpc\": \"2.0\", \"method\": \"mnr_getWork\", \"params\": [], \"id\": 1}";
// }

bool GwMaker::rskdRpcGw(string &response)
{
  //string request = constructRequest();
  bool res = rpcCall(gwDef_.addr.c_str(),
                     gwDef_.userpwd.c_str(),
                     gwDef_.data.empty() ? nullptr : gwDef_.data.c_str(),
                     response,
                     gwDef_.agent.c_str());

  if (!res)
  {
    LOG(ERROR) << "rskd RPC failure";
    return false;
  }
  return true;
}

bool GwMaker::checkFields(JsonNode &r) {
  if (r["result"].type()                                != Utilities::JS::type::Obj ||
      r["result"]["parentBlockHash"].type()             != Utilities::JS::type::Str ||
      r["result"]["blockHashForMergedMining"].type()    != Utilities::JS::type::Str ||
      r["result"]["target"].type()                      != Utilities::JS::type::Str ||
      r["result"]["feesPaidToMiner"].type()             != Utilities::JS::type::Str ||
      r["result"]["notify"].type()                      != Utilities::JS::type::Bool) {
    return false;
  }

  return true;
}

string GwMaker::constructRawMsg(string &gw, JsonNode &r) {
  const uint256 gwHash = Hash(gw.begin(), gw.end());

  LOG(INFO) << ", parent block hash: "    << r["result"]["parentBlockHash"].str()
  << ", block hash for merge mining: " << r["result"]["blockHashForMergedMining"].str()
  << ", target: "               << r["result"]["target"].str()
  << ", fees paid to miner: "   << r["result"]["feesPaidToMiner"].str()
  << ", notify: " << r["result"]["notify"].boolean()
  << ", gwhash: " << gwHash.ToString();

  return Strings::Format("{\"created_at_ts\":%u,"
                         "\"rskdRpcAddress\":\"%s\","
                         "\"rskdRpcUserPwd\":\"%s\","
                         "\"target\":\"%s\","
                         "\"parentBlockHash\":\"%s\","
                         "\"blockHashForMergedMining\":\"%s\","
                         "\"feesPaidToMiner\":\"%s\","
                         "\"notify\":\"%s\"}",
                         (uint32_t)time(nullptr),
                         rskdRpcAddr_.c_str(),
                         rskdRpcUserpass_.c_str(),
                         r["result"]["target"].str().c_str(),
                         r["result"]["parentBlockHash"].str().c_str(),
                         r["result"]["blockHashForMergedMining"].str().c_str(),
                         r["result"]["feesPaidToMiner"].str().c_str(),
                         r["result"]["notify"].boolean() ? "true" : "false");
}

string GwMaker::makeRawGwMsg() {
  string gw;
  if (!rskdRpcGw(gw)) {
    return "";
  }

  LOG(INFO) << "getwork len: " << gw.length() << ", buf" << gw;

  return gwDef_.handler ? gwDef_.handler->processRawMsg(gwDef_, gw) : "";
}

void GwMaker::submitRawGwMsg() {

  const string rawGwMsg = makeRawGwMsg();
  if (rawGwMsg.length() == 0) {
    LOG(ERROR) << "get rawGw failure";
    return;
  }

  // submit to Kafka
  LOG(INFO) << "submit to Kafka msg len: " << rawGwMsg.length();
  kafkaProduceMsg(rawGwMsg.c_str(), rawGwMsg.length());
}

void GwMaker::run() {

  while (running_) {
    usleep(gwDef_.interval * 1000);
    submitRawGwMsg();
  }
}

///////////////////////////////GwHandlerEth////////////////////////////////////
string GwHandlerEth::processRawMsg(const GwDefinition& def, const string& msg)
{
  JsonNode r;
  if (!JsonNode::parse(msg.c_str(), msg.c_str() + msg.length(), r)) {
    LOG(ERROR) << "decode gw failure: " << msg;
    return "";
  }

  //LOG(INFO) << "result type: " << (int)r["result"].type();
  //LOG(INFO) << "parse result: " << r["result"].str();

  // check fields
  if (!checkFields(r)) {
    LOG(ERROR) << "gw check fields failure";
    return "";
  }

  return constructRawMsg(def, r);
}

// GwMakerEth::GwMakerEth(const string &rskdRpcAddr, const string &rskdRpcUserpass,
//                        const string &kafkaBrokers, uint32_t kRpcCallInterval) : GwMaker(rskdRpcAddr, rskdRpcUserpass, kafkaBrokers, kRpcCallInterval)
// {
// }

// string GwMakerEth::constructRequest()
// {
//   return "{\"jsonrpc\": \"2.0\", \"method\": \"eth_getWork\", \"params\": [], \"id\": 1}";
// }

bool GwHandlerEth::checkFields(JsonNode &r)
{
  // Ethereum's GetWork gives us 3 values:

  // { ... "result":[
  // "0x645cf20198c2f3861e947d4f67e3ab63b7b2e24dcc9095bd9123e7b33371f6cc",
  // "0xabad8f99f3918bf903c6a909d9bbc0fdfa5a2f4b9cb1196175ec825c6610126c",
  // "0x0000000394427b08175efa9a9eb59b9123e2969bf19bf272b20787ed022fbe6c"
  // ]}

  // First value is headerhash, second value is seedhash and third value is
  // target. Seedhash is used to identify DAG file, headerhash and 64 bit
  // nonce value chosen by our miner give us hash, which, if below provided
  // target, yield block/share.

  // error
  // {
  //     "jsonrpc": "2.0",
  //     "id": 73,
  //     "error": {
  //         "code": -32000,
  //         "message": "mining not ready: No work available yet, don't panic."
  //     }
  // }
  if (r.type() != Utilities::JS::type::Obj)
  {
    LOG(ERROR) << "getwork return not jason";
    return false;
  }

  JsonNode result = r["result"];
  if (result["error"].type() == Utilities::JS::type::Obj &&
      result["error"]["message"].type() == Utilities::JS::type::Str)
  {
    LOG(ERROR) << result["error"]["message"].str();
    return false;
  }

  if (r.type() != Utilities::JS::type::Obj ||
      r["result"].type() != Utilities::JS::type::Array ||
      r["result"].array().size() != 3)
  {
    LOG(ERROR) << "getwork retrun unexpected";
    return false;
  }

  return true;
}

string GwHandlerEth::constructRawMsg(const GwDefinition& def, JsonNode &r) {
  // const uint256 gwHash = Hash(gw.begin(), gw.end());
  // LOG(INFO) << "gwhash: " << gwHash.ToString();
  auto result = r["result"].array();
  return Strings::Format("{\"created_at_ts\":%u,"
                         "\"rskdRpcAddress\":\"%s\","
                         "\"rskdRpcUserPwd\":\"%s\","
                         "\"target\":\"%s\","
                         "\"hHash\":\"%s\","
                         "\"sHash\":\"%s\"}",
                         (uint32_t)time(nullptr),
                         def.addr.c_str(),
                         def.userpwd.c_str(),
                         result[2].str().c_str(),
                         result[0].str().c_str(),
                         result[1].str().c_str());
}

///////////////////////////////GwHandlerSia////////////////////////////////////
string GwHandlerSia::processRawMsg(const GwDefinition& def, const string& msg)
{
//   Field	Byte range within response	Byte range within header
// target	[0-32)
// header	[32-112)
// parent block ID	[32-64)	[0-32)
// nonce	[64-72)	[32-40)
// timestamp	[72-80)	[40-48)
// merkle root	[80-112)	[48-80)
  string targetStr;
  for (int i = 0; i < 32; ++i) {
    uint8 val = (uint8) msg[i];
    targetStr += Strings::Format("%02x", val);
  }

  LOG(INFO) << "Sia work target length: " << targetStr.length() << ", value : 0x" << targetStr;

  //  = msg.substr(0, 32);
  // string parentIdStr = msg.substr(32, 32);
  // string parentIdStr = msg.substr(32, 32);

  return "";
}<commit_msg>block id<commit_after>/*
 The MIT License (MIT)

 Copyright (C) 2017 RSK Labs Ltd.

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 */

/**
  File: GwMaker.cc
  Purpose: Poll RSK node to get new work and send it to Kafka "RawGw" topic

  @author Martin Medina
  @copyright RSK Labs Ltd.
  @version 1.0 30/03/17
*/

#include "GwMaker.h"

#include <glog/logging.h>
#include <util.h>
#include <utilstrencodings.h>
#include "Utils.h"

// GwMaker::GwMaker(const string &rskdRpcAddr, const string &rskdRpcUserpass,
//                    const string &kafkaBrokers, uint32_t kRpcCallInterval)
// : running_(true), rskdRpcAddr_(rskdRpcAddr),
// rskdRpcUserpass_(rskdRpcUserpass), kRpcCallInterval_(kRpcCallInterval),
// kafkaBrokers_(kafkaBrokers),
// kafkaProducer_(kafkaBrokers_.c_str(), KAFKA_TOPIC_RAWGW, 0/* partition */)
// {
// }

GwMaker::GwMaker(const GwDefinition gwDef) : gwDef_(gwDef),
                                             running_(true),
                                             kafkaProducer_(gwDef.broker.c_str(), gwDef.topic.c_str(), 0 /* partition */)
{
}

GwMaker::~GwMaker() {}

bool GwMaker::init() {
  map<string, string> options;
  // set to 1 (0 is an illegal value here), deliver msg as soon as possible.
  options["queue.buffering.max.ms"] = "1";
  if (!kafkaProducer_.setup(&options)) {
    LOG(ERROR) << "kafka producer setup failure";
    return false;
  }

  // setup kafka and check if it's alive
  if (!kafkaProducer_.checkAlive()) {
    LOG(ERROR) << "kafka is NOT alive";
    return false;
  }

  // TODO: check rskd is alive in a similar way as done for btcd

  return true;
}

void GwMaker::stop() {
  if (!running_) {
    return;
  }
  running_ = false;
  LOG(INFO) << "stop GwMaker";
}

void GwMaker::kafkaProduceMsg(const void *payload, size_t len) {
  kafkaProducer_.produce(payload, len);
}

// string GwMaker::constructRequest() {
//   //return "{\"jsonrpc\": \"2.0\", \"method\": \"mnr_getWork\", \"params\": [], \"id\": 1}";
// }

bool GwMaker::rskdRpcGw(string &response)
{
  //string request = constructRequest();
  bool res = rpcCall(gwDef_.addr.c_str(),
                     gwDef_.userpwd.c_str(),
                     gwDef_.data.empty() ? nullptr : gwDef_.data.c_str(),
                     response,
                     gwDef_.agent.c_str());

  if (!res)
  {
    LOG(ERROR) << "rskd RPC failure";
    return false;
  }
  return true;
}

bool GwMaker::checkFields(JsonNode &r) {
  if (r["result"].type()                                != Utilities::JS::type::Obj ||
      r["result"]["parentBlockHash"].type()             != Utilities::JS::type::Str ||
      r["result"]["blockHashForMergedMining"].type()    != Utilities::JS::type::Str ||
      r["result"]["target"].type()                      != Utilities::JS::type::Str ||
      r["result"]["feesPaidToMiner"].type()             != Utilities::JS::type::Str ||
      r["result"]["notify"].type()                      != Utilities::JS::type::Bool) {
    return false;
  }

  return true;
}

string GwMaker::constructRawMsg(string &gw, JsonNode &r) {
  const uint256 gwHash = Hash(gw.begin(), gw.end());

  LOG(INFO) << ", parent block hash: "    << r["result"]["parentBlockHash"].str()
  << ", block hash for merge mining: " << r["result"]["blockHashForMergedMining"].str()
  << ", target: "               << r["result"]["target"].str()
  << ", fees paid to miner: "   << r["result"]["feesPaidToMiner"].str()
  << ", notify: " << r["result"]["notify"].boolean()
  << ", gwhash: " << gwHash.ToString();

  return Strings::Format("{\"created_at_ts\":%u,"
                         "\"rskdRpcAddress\":\"%s\","
                         "\"rskdRpcUserPwd\":\"%s\","
                         "\"target\":\"%s\","
                         "\"parentBlockHash\":\"%s\","
                         "\"blockHashForMergedMining\":\"%s\","
                         "\"feesPaidToMiner\":\"%s\","
                         "\"notify\":\"%s\"}",
                         (uint32_t)time(nullptr),
                         rskdRpcAddr_.c_str(),
                         rskdRpcUserpass_.c_str(),
                         r["result"]["target"].str().c_str(),
                         r["result"]["parentBlockHash"].str().c_str(),
                         r["result"]["blockHashForMergedMining"].str().c_str(),
                         r["result"]["feesPaidToMiner"].str().c_str(),
                         r["result"]["notify"].boolean() ? "true" : "false");
}

string GwMaker::makeRawGwMsg() {
  string gw;
  if (!rskdRpcGw(gw)) {
    return "";
  }

  LOG(INFO) << "getwork len: " << gw.length() << ", buf" << gw;

  return gwDef_.handler ? gwDef_.handler->processRawMsg(gwDef_, gw) : "";
}

void GwMaker::submitRawGwMsg() {

  const string rawGwMsg = makeRawGwMsg();
  if (rawGwMsg.length() == 0) {
    LOG(ERROR) << "get rawGw failure";
    return;
  }

  // submit to Kafka
  LOG(INFO) << "submit to Kafka msg len: " << rawGwMsg.length();
  kafkaProduceMsg(rawGwMsg.c_str(), rawGwMsg.length());
}

void GwMaker::run() {

  while (running_) {
    usleep(gwDef_.interval * 1000);
    submitRawGwMsg();
  }
}

///////////////////////////////GwHandlerEth////////////////////////////////////
string GwHandlerEth::processRawMsg(const GwDefinition& def, const string& msg)
{
  JsonNode r;
  if (!JsonNode::parse(msg.c_str(), msg.c_str() + msg.length(), r)) {
    LOG(ERROR) << "decode gw failure: " << msg;
    return "";
  }

  //LOG(INFO) << "result type: " << (int)r["result"].type();
  //LOG(INFO) << "parse result: " << r["result"].str();

  // check fields
  if (!checkFields(r)) {
    LOG(ERROR) << "gw check fields failure";
    return "";
  }

  return constructRawMsg(def, r);
}

// GwMakerEth::GwMakerEth(const string &rskdRpcAddr, const string &rskdRpcUserpass,
//                        const string &kafkaBrokers, uint32_t kRpcCallInterval) : GwMaker(rskdRpcAddr, rskdRpcUserpass, kafkaBrokers, kRpcCallInterval)
// {
// }

// string GwMakerEth::constructRequest()
// {
//   return "{\"jsonrpc\": \"2.0\", \"method\": \"eth_getWork\", \"params\": [], \"id\": 1}";
// }

bool GwHandlerEth::checkFields(JsonNode &r)
{
  // Ethereum's GetWork gives us 3 values:

  // { ... "result":[
  // "0x645cf20198c2f3861e947d4f67e3ab63b7b2e24dcc9095bd9123e7b33371f6cc",
  // "0xabad8f99f3918bf903c6a909d9bbc0fdfa5a2f4b9cb1196175ec825c6610126c",
  // "0x0000000394427b08175efa9a9eb59b9123e2969bf19bf272b20787ed022fbe6c"
  // ]}

  // First value is headerhash, second value is seedhash and third value is
  // target. Seedhash is used to identify DAG file, headerhash and 64 bit
  // nonce value chosen by our miner give us hash, which, if below provided
  // target, yield block/share.

  // error
  // {
  //     "jsonrpc": "2.0",
  //     "id": 73,
  //     "error": {
  //         "code": -32000,
  //         "message": "mining not ready: No work available yet, don't panic."
  //     }
  // }
  if (r.type() != Utilities::JS::type::Obj)
  {
    LOG(ERROR) << "getwork return not jason";
    return false;
  }

  JsonNode result = r["result"];
  if (result["error"].type() == Utilities::JS::type::Obj &&
      result["error"]["message"].type() == Utilities::JS::type::Str)
  {
    LOG(ERROR) << result["error"]["message"].str();
    return false;
  }

  if (r.type() != Utilities::JS::type::Obj ||
      r["result"].type() != Utilities::JS::type::Array ||
      r["result"].array().size() != 3)
  {
    LOG(ERROR) << "getwork retrun unexpected";
    return false;
  }

  return true;
}

string GwHandlerEth::constructRawMsg(const GwDefinition& def, JsonNode &r) {
  // const uint256 gwHash = Hash(gw.begin(), gw.end());
  // LOG(INFO) << "gwhash: " << gwHash.ToString();
  auto result = r["result"].array();
  return Strings::Format("{\"created_at_ts\":%u,"
                         "\"rskdRpcAddress\":\"%s\","
                         "\"rskdRpcUserPwd\":\"%s\","
                         "\"target\":\"%s\","
                         "\"hHash\":\"%s\","
                         "\"sHash\":\"%s\"}",
                         (uint32_t)time(nullptr),
                         def.addr.c_str(),
                         def.userpwd.c_str(),
                         result[2].str().c_str(),
                         result[0].str().c_str(),
                         result[1].str().c_str());
}

///////////////////////////////GwHandlerSia////////////////////////////////////
string GwHandlerSia::processRawMsg(const GwDefinition& def, const string& msg)
{
//   Field	Byte range within response	Byte range within header
// target	[0-32)
// header	[32-112)
// parent block ID	[32-64)	[0-32)
// nonce	[64-72)	[32-40)
// timestamp	[72-80)	[40-48)
// merkle root	[80-112)	[48-80)
  string targetStr;
  for (int i = 0; i < 32; ++i) {
    uint8 val = (uint8) msg[i];
    targetStr += Strings::Format("%02x", val);
  }

  string blkIdStr;
  for (int i = 32; i < 64; ++i) {
    uint8 val = (uint8) msg[i];
    blkIdStr += Strings::Format("%02x", val);
  }

  LOG(INFO) << "Sia work target 0x" << targetStr << ", blkId 0x" << blkIdStr;

  //  = msg.substr(0, 32);
  // string parentIdStr = msg.substr(32, 32);
  // string parentIdStr = msg.substr(32, 32);

  return "";
}<|endoftext|>


<commit_before>
//
// This source file is part of appleseed.
// Visit https://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2018 Francois Beaune, The appleseedhq Organization
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "searchpathswindow.h"

// UI definition headers.
#include "ui_searchpathswindow.h"

// appleseed.studio headers.
#include "utility/miscellaneous.h"

// appleseed.renderer headers.
#include "renderer/api/project.h"

// appleseed.foundation headers.
#include "foundation/utility/searchpaths.h"

// Qt headers.
#include <QKeySequence>
#include <QLineEdit>
#include <QShortcut>
#include <QString>
#include <Qt>

using namespace renderer;

namespace appleseed {
namespace studio {

//
// SearchPathsWindow class implementation.
//

namespace
{
    QListWidgetItem* make_item(const QString& text = QString())
    {
        auto item = new QListWidgetItem(text);
        item->setFlags(item->flags() | Qt::ItemIsEditable);
        return item;
    }
}

SearchPathsWindow::SearchPathsWindow(
    const Project&  project,
    QWidget*        parent)
  : WindowBase(parent, "search_paths_window")
  , m_ui(new Ui::SearchPathsWindow())
  , m_project(project)
  , m_edit_committed(false)
{
    m_ui->setupUi(this);

    setWindowFlags(Qt::Window);

    // Buttons.
    connect(m_ui->pushbutton_add, SIGNAL(clicked()), SLOT(slot_add()));
    connect(m_ui->pushbutton_remove, SIGNAL(clicked()), SLOT(slot_remove()));
    connect(m_ui->pushbutton_moveup, SIGNAL(clicked()), SLOT(slot_move_up()));
    connect(m_ui->pushbutton_movedown, SIGNAL(clicked()), SLOT(slot_move_down()));

    // List widget.
    connect(
        m_ui->listwidget_paths, SIGNAL(itemSelectionChanged()),
        SLOT(slot_path_selection_changed()));
    connect(
        m_ui->listwidget_paths->itemDelegate(), SIGNAL(commitData(QWidget*)),
        SLOT(slot_path_editor_committed(QWidget*)));
    connect(
        m_ui->listwidget_paths->itemDelegate(), SIGNAL(closeEditor(QWidget*)),
        SLOT(slot_path_editor_closed(QWidget*)));

    // Keyboard shortcuts.
    connect(create_window_local_shortcut(this, Qt::Key_Escape), SIGNAL(activated()), SLOT(reject()));
    connect(new QShortcut(QKeySequence(Qt::Key_Delete), this), SIGNAL(activated()), SLOT(slot_remove()));
    connect(new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Up), this), SIGNAL(activated()), SLOT(slot_move_up()));
    connect(new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Down), this), SIGNAL(activated()), SLOT(slot_move_down()));

    WindowBase::load_settings();

    // Project root path.
    if (m_project.search_paths().has_root_path())
    {
        const auto root_path = m_project.search_paths().get_root_path();
        m_ui->lineedit_root_path->setText(root_path.c_str());
        m_ui->lineedit_root_path->setProperty("isSet", true);
    }
    else
    {
        m_ui->lineedit_root_path->setText("Not Set");
        m_ui->lineedit_root_path->setProperty("isSet", false);
    }

    // Populate list widget with search paths from project.
    load_search_paths();

    slot_path_selection_changed();
}

SearchPathsWindow::~SearchPathsWindow()
{
    delete m_ui;
}

void SearchPathsWindow::load_search_paths()
{
    const auto& search_paths = m_project.search_paths();

    m_ui->listwidget_paths->clear();

    for (size_t i = 0, e = search_paths.get_path_count(); i < e; ++i)
    {
        auto item = make_item(search_paths.get_path(i));

        // Environment search paths are grayed out and cannot be removed, edited or moved.
        if (i < search_paths.get_environment_path_count())
            item->setFlags(item->flags() & ~Qt::ItemIsEnabled);

        m_ui->listwidget_paths->addItem(item);
    }
}

void SearchPathsWindow::save_search_paths()
{
    auto& search_paths = m_project.search_paths();

    search_paths.clear_explicit_paths();

    for (int i = 0, e = m_ui->listwidget_paths->count(); i < e; ++i)
        search_paths.push_back_explicit_path(m_ui->listwidget_paths->item(i)->text().toStdString());

    emit signal_paths_modified();
}

void SearchPathsWindow::accept()
{
    save_search_paths();
    close();
}

void SearchPathsWindow::reject()
{
    load_search_paths();
    close();
}

void SearchPathsWindow::slot_add()
{
    auto item = make_item();
    m_ui->listwidget_paths->addItem(item);
    m_ui->listwidget_paths->setCurrentItem(item);

    m_ui->pushbutton_add->setEnabled(false);
    m_ui->pushbutton_remove->setEnabled(false);
    m_ui->pushbutton_moveup->setEnabled(false);
    m_ui->pushbutton_movedown->setEnabled(false);

    m_edit_committed = false;
    m_ui->listwidget_paths->editItem(item);
}

void SearchPathsWindow::slot_remove()
{
    for (auto selected_item : m_ui->listwidget_paths->selectedItems())
        delete selected_item;

    slot_path_selection_changed();
}

void SearchPathsWindow::slot_move_up()
{
    const auto index = m_ui->listwidget_paths->currentRow();

    const auto first_editable_path_index =
        static_cast<int>(m_project.search_paths().get_environment_path_count());

    if (index > first_editable_path_index)
    {
        auto item = m_ui->listwidget_paths->takeItem(index);
        m_ui->listwidget_paths->insertItem(index - 1, item);
        m_ui->listwidget_paths->setCurrentItem(item);
    }
}

void SearchPathsWindow::slot_move_down()
{
    const auto index = m_ui->listwidget_paths->currentRow();

    if (index < m_ui->listwidget_paths->count() - 1)
    {
        auto item = m_ui->listwidget_paths->takeItem(index);
        m_ui->listwidget_paths->insertItem(index + 1, item);
        m_ui->listwidget_paths->setCurrentItem(item);
    }
}

void SearchPathsWindow::slot_path_selection_changed()
{
    const auto index = m_ui->listwidget_paths->currentRow();

    const auto first_editable_path_index =
        static_cast<int>(m_project.search_paths().get_environment_path_count());

    m_ui->pushbutton_add->setEnabled(true);
    m_ui->pushbutton_remove->setEnabled(index != -1);
    m_ui->pushbutton_moveup->setEnabled(index > first_editable_path_index);
    m_ui->pushbutton_movedown->setEnabled(index != -1 && index < m_ui->listwidget_paths->count() - 1);
}

void SearchPathsWindow::slot_path_editor_committed(QWidget* widget)
{
    m_edit_committed = true;
}

void SearchPathsWindow::slot_path_editor_closed(QWidget* widget)
{
    const QString path = reinterpret_cast<QLineEdit*>(widget)->text();

    if (!m_edit_committed || path.isEmpty())
        delete m_ui->listwidget_paths->currentItem();

    slot_path_selection_changed();
}

}   // namespace studio
}   // namespace appleseed

#include "mainwindow/project/moc_cpp_searchpathswindow.cxx"
<commit_msg>CTRL+Enter now closes appleseed.studio's Search Paths editor<commit_after>
//
// This source file is part of appleseed.
// Visit https://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2018 Francois Beaune, The appleseedhq Organization
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "searchpathswindow.h"

// UI definition headers.
#include "ui_searchpathswindow.h"

// appleseed.studio headers.
#include "utility/miscellaneous.h"

// appleseed.renderer headers.
#include "renderer/api/project.h"

// appleseed.foundation headers.
#include "foundation/utility/searchpaths.h"

// Qt headers.
#include <QKeySequence>
#include <QLineEdit>
#include <QShortcut>
#include <QString>
#include <Qt>

using namespace renderer;

namespace appleseed {
namespace studio {

//
// SearchPathsWindow class implementation.
//

namespace
{
    QListWidgetItem* make_item(const QString& text = QString())
    {
        auto item = new QListWidgetItem(text);
        item->setFlags(item->flags() | Qt::ItemIsEditable);
        return item;
    }
}

SearchPathsWindow::SearchPathsWindow(
    const Project&  project,
    QWidget*        parent)
  : WindowBase(parent, "search_paths_window")
  , m_ui(new Ui::SearchPathsWindow())
  , m_project(project)
  , m_edit_committed(false)
{
    m_ui->setupUi(this);

    setWindowFlags(Qt::Window);

    // Buttons.
    connect(m_ui->pushbutton_add, SIGNAL(clicked()), SLOT(slot_add()));
    connect(m_ui->pushbutton_remove, SIGNAL(clicked()), SLOT(slot_remove()));
    connect(m_ui->pushbutton_moveup, SIGNAL(clicked()), SLOT(slot_move_up()));
    connect(m_ui->pushbutton_movedown, SIGNAL(clicked()), SLOT(slot_move_down()));

    // List widget.
    connect(
        m_ui->listwidget_paths, SIGNAL(itemSelectionChanged()),
        SLOT(slot_path_selection_changed()));
    connect(
        m_ui->listwidget_paths->itemDelegate(), SIGNAL(commitData(QWidget*)),
        SLOT(slot_path_editor_committed(QWidget*)));
    connect(
        m_ui->listwidget_paths->itemDelegate(), SIGNAL(closeEditor(QWidget*)),
        SLOT(slot_path_editor_closed(QWidget*)));

    // Keyboard shortcuts.
    connect(create_window_local_shortcut(this, Qt::Key_Escape), SIGNAL(activated()), SLOT(reject()));
    connect(new QShortcut(QKeySequence(Qt::Key_Delete), this), SIGNAL(activated()), SLOT(slot_remove()));
    connect(new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Up), this), SIGNAL(activated()), SLOT(slot_move_up()));
    connect(new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Down), this), SIGNAL(activated()), SLOT(slot_move_down()));
    connect(new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Return), this), SIGNAL(activated()), SLOT(accept()));
    connect(new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Enter), this), SIGNAL(activated()), SLOT(accept()));

    WindowBase::load_settings();

    // Project root path.
    if (m_project.search_paths().has_root_path())
    {
        const auto root_path = m_project.search_paths().get_root_path();
        m_ui->lineedit_root_path->setText(root_path.c_str());
        m_ui->lineedit_root_path->setProperty("isSet", true);
    }
    else
    {
        m_ui->lineedit_root_path->setText("Not Set");
        m_ui->lineedit_root_path->setProperty("isSet", false);
    }

    // Populate list widget with search paths from project.
    load_search_paths();

    slot_path_selection_changed();
}

SearchPathsWindow::~SearchPathsWindow()
{
    delete m_ui;
}

void SearchPathsWindow::load_search_paths()
{
    const auto& search_paths = m_project.search_paths();

    m_ui->listwidget_paths->clear();

    for (size_t i = 0, e = search_paths.get_path_count(); i < e; ++i)
    {
        auto item = make_item(search_paths.get_path(i));

        // Environment search paths are grayed out and cannot be removed, edited or moved.
        if (i < search_paths.get_environment_path_count())
            item->setFlags(item->flags() & ~Qt::ItemIsEnabled);

        m_ui->listwidget_paths->addItem(item);
    }
}

void SearchPathsWindow::save_search_paths()
{
    auto& search_paths = m_project.search_paths();

    search_paths.clear_explicit_paths();

    for (int i = 0, e = m_ui->listwidget_paths->count(); i < e; ++i)
        search_paths.push_back_explicit_path(m_ui->listwidget_paths->item(i)->text().toStdString());

    emit signal_paths_modified();
}

void SearchPathsWindow::accept()
{
    save_search_paths();
    close();
}

void SearchPathsWindow::reject()
{
    load_search_paths();
    close();
}

void SearchPathsWindow::slot_add()
{
    auto item = make_item();
    m_ui->listwidget_paths->addItem(item);
    m_ui->listwidget_paths->setCurrentItem(item);

    m_ui->pushbutton_add->setEnabled(false);
    m_ui->pushbutton_remove->setEnabled(false);
    m_ui->pushbutton_moveup->setEnabled(false);
    m_ui->pushbutton_movedown->setEnabled(false);

    m_edit_committed = false;
    m_ui->listwidget_paths->editItem(item);
}

void SearchPathsWindow::slot_remove()
{
    for (auto selected_item : m_ui->listwidget_paths->selectedItems())
        delete selected_item;

    slot_path_selection_changed();
}

void SearchPathsWindow::slot_move_up()
{
    const auto index = m_ui->listwidget_paths->currentRow();

    const auto first_editable_path_index =
        static_cast<int>(m_project.search_paths().get_environment_path_count());

    if (index > first_editable_path_index)
    {
        auto item = m_ui->listwidget_paths->takeItem(index);
        m_ui->listwidget_paths->insertItem(index - 1, item);
        m_ui->listwidget_paths->setCurrentItem(item);
    }
}

void SearchPathsWindow::slot_move_down()
{
    const auto index = m_ui->listwidget_paths->currentRow();

    if (index < m_ui->listwidget_paths->count() - 1)
    {
        auto item = m_ui->listwidget_paths->takeItem(index);
        m_ui->listwidget_paths->insertItem(index + 1, item);
        m_ui->listwidget_paths->setCurrentItem(item);
    }
}

void SearchPathsWindow::slot_path_selection_changed()
{
    const auto index = m_ui->listwidget_paths->currentRow();

    const auto first_editable_path_index =
        static_cast<int>(m_project.search_paths().get_environment_path_count());

    m_ui->pushbutton_add->setEnabled(true);
    m_ui->pushbutton_remove->setEnabled(index != -1);
    m_ui->pushbutton_moveup->setEnabled(index > first_editable_path_index);
    m_ui->pushbutton_movedown->setEnabled(index != -1 && index < m_ui->listwidget_paths->count() - 1);
}

void SearchPathsWindow::slot_path_editor_committed(QWidget* widget)
{
    m_edit_committed = true;
}

void SearchPathsWindow::slot_path_editor_closed(QWidget* widget)
{
    const QString path = reinterpret_cast<QLineEdit*>(widget)->text();

    if (!m_edit_committed || path.isEmpty())
        delete m_ui->listwidget_paths->currentItem();

    slot_path_selection_changed();
}

}   // namespace studio
}   // namespace appleseed

#include "mainwindow/project/moc_cpp_searchpathswindow.cxx"
<|endoftext|>


<commit_before>#include "inject.h"

namespace {

possumwood::lua::Inject<unsigned> s_unsignedInject;
possumwood::lua::Inject<float> s_floatInject;

possumwood::NodeImplementation s_impl_unsigned("lua/inject/unsigned",
                                               [](possumwood::Metadata& meta) { s_unsignedInject.init(meta); });
possumwood::NodeImplementation s_impl_float("lua/inject/float",
                                            [](possumwood::Metadata& meta) { s_floatInject.init(meta); });

}  // namespace
<commit_msg>Added lua bool (checkbox) injection<commit_after>#include "inject.h"

namespace {

possumwood::lua::Inject<unsigned> s_unsignedInject;
possumwood::lua::Inject<float> s_floatInject;
possumwood::lua::Inject<bool> s_boolInject;

possumwood::NodeImplementation s_impl_unsigned("lua/inject/unsigned",
                                               [](possumwood::Metadata& meta) { s_unsignedInject.init(meta); });
possumwood::NodeImplementation s_impl_float("lua/inject/float",
                                            [](possumwood::Metadata& meta) { s_floatInject.init(meta); });
possumwood::NodeImplementation s_impl_bool("lua/inject/bool",
                                           [](possumwood::Metadata& meta) { s_boolInject.init(meta); });

}  // namespace
<|endoftext|>


<commit_before>/*
 * Asynchronous local file access.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "istream_file.hxx"
#include "istream_buffer.hxx"
#include "buffered_io.hxx"
#include "system/fd_util.h"
#include "gerrno.h"
#include "pool.hxx"
#include "fb_pool.hxx"
#include "SliceFifoBuffer.hxx"
#include "util/Cast.hxx"

#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <limits.h>

#include <event.h>

/**
 * If EAGAIN occurs (on NFS), we try again after 100ms.  We can't
 * check EV_READ, because the kernel always indicates VFS files as
 * "readable without blocking".
 */
static const struct timeval file_retry_timeout = {
    .tv_sec = 0,
    .tv_usec = 100000,
};

struct FileIstream {
    struct istream stream;
    int fd;

    FdType fd_type;

    /**
     * A timer to retry reading after EAGAIN.
     */
    struct event event;

    off_t rest;
    SliceFifoBuffer buffer;
    const char *path;

    void CloseHandle() {
        if (fd < 0)
            return;

        evtimer_del(&event);

        close(fd);
        fd = -1;

        buffer.FreeIfDefined(fb_pool_get());
    }

    void Abort(GError *error) {
        CloseHandle();

        istream_deinit_abort(&stream, error);
    }

    /**
     * @return the number of bytes still in the buffer
     */
    size_t SubmitBuffer() {
        return istream_buffer_consume(&stream, buffer);
    }

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

        CloseHandle();
        istream_deinit_eof(&stream);
    }

    gcc_pure
    size_t GetMaxRead() const {
        if (rest != (off_t)-1 && rest < (off_t)INT_MAX)
            return (size_t)rest;
        else
            return INT_MAX;
    }

    void TryData();
    void TryDirect();

    void TryRead() {
        if (istream_check_direct(&stream, fd_type))
            TryDirect();
        else
            TryData();
    }
};

inline void
FileIstream::TryData()
{
    size_t buffer_rest = 0;

    if (buffer.IsNull()) {
        if (rest != 0)
            buffer.Allocate(fb_pool_get());
    } else {
        const size_t available = buffer.GetAvailable();
        if (available > 0) {
            buffer_rest = SubmitBuffer();
            if (buffer_rest == available)
                /* not a single byte was consumed: we may have been
                   closed, and we must bail out now */
                return;
        }
    }

    if (rest == 0) {
        if (buffer_rest == 0)
            EofDetected();
        return;
    }

    ssize_t nbytes = read_to_buffer(fd, buffer, GetMaxRead());
    if (nbytes == 0) {
        if (rest == (off_t)-1) {
            rest = 0;
            if (buffer_rest == 0)
                EofDetected();
        } else {
            GError *error =
                g_error_new(g_file_error_quark(), 0,
                            "premature end of file in '%s'", path);
            Abort(error);
        }
        return;
    } else if (nbytes == -1) {
        GError *error =
            g_error_new(errno_quark(), errno,
                        "failed to read from '%s': %s",
                        path, strerror(errno));
        Abort(error);
        return;
    } else if (nbytes > 0 && rest != (off_t)-1) {
        rest -= (off_t)nbytes;
        assert(rest >= 0);
    }

    assert(!buffer.IsEmpty());

    buffer_rest = SubmitBuffer();
    if (buffer_rest == 0 && rest == 0)
        EofDetected();
}

inline void
FileIstream::TryDirect()
{
    assert(stream.handler->direct != nullptr);

    /* first consume the rest of the buffer */
    if (SubmitBuffer() > 0)
        return;

    if (rest == 0) {
        EofDetected();
        return;
    }

    ssize_t nbytes = istream_invoke_direct(&stream,
                                           fd_type, fd,
                                           GetMaxRead());
    if (nbytes == ISTREAM_RESULT_CLOSED)
        /* this stream was closed during the direct() callback */
        return;

    if (nbytes > 0 || nbytes == ISTREAM_RESULT_BLOCKING) {
        /* -2 means the callback wasn't able to consume any data right
           now */
        if (nbytes > 0 && rest != (off_t)-1) {
            rest -= (off_t)nbytes;
            assert(rest >= 0);
            if (rest == 0)
                EofDetected();
        }
    } else if (nbytes == ISTREAM_RESULT_EOF) {
        if (rest == (off_t)-1) {
            EofDetected();
        } else {
            GError *error =
                g_error_new(g_file_error_quark(), 0,
                            "premature end of file in '%s'", path);
            Abort(error);
        }
    } else if (errno == EAGAIN) {
        /* this should only happen for splice(SPLICE_F_NONBLOCK) from
           NFS files - unfortunately we cannot use EV_READ here, so we
           just install a timer which retries after 100ms */

        evtimer_add(&event, &file_retry_timeout);
    } else {
        /* XXX */
        GError *error =
            g_error_new(errno_quark(), errno,
                        "failed to read from '%s': %s",
                        path, strerror(errno));
        Abort(error);
    }
}

static void
file_event_callback(gcc_unused int fd, gcc_unused short event,
                    void *ctx)
{
    FileIstream *file = (FileIstream *)ctx;

    file->TryRead();
}

/*
 * istream implementation
 *
 */

static inline FileIstream *
istream_to_file(struct istream *istream)
{
    return &ContainerCast2(*istream, &FileIstream::stream);
}

static off_t
istream_file_available(struct istream *istream, bool partial)
{
    FileIstream *file = istream_to_file(istream);
    off_t available = 0;

    if (file->rest != (off_t)-1)
        available = file->rest;
    else if (!partial)
        return (off_t)-1;
    else
        available = 0;

    available += file->buffer.GetAvailable();
    return available;
}

static off_t
istream_file_skip(struct istream *istream, off_t length)
{
    FileIstream *file = istream_to_file(istream);

    evtimer_del(&file->event);

    if (file->rest == (off_t)-1)
        return (off_t)-1;

    if (length == 0)
        return 0;

    /* clear the buffer; later we could optimize this function by
       flushing only the skipped number of bytes */
    file->buffer.Clear();

    if (length >= file->rest) {
        /* skip beyond EOF */

        length = file->rest;
        file->rest = 0;
    } else {
        /* seek the file descriptor */

        off_t ret = lseek(file->fd, length, SEEK_CUR);
        if (ret < 0)
            return -1;
        file->rest -= length;
    }

    return length;
}

static void
istream_file_read(struct istream *istream)
{
    FileIstream *file = istream_to_file(istream);

    assert(file->stream.handler != nullptr);

    evtimer_del(&file->event);

    file->TryRead();
}

static int
istream_file_as_fd(struct istream *istream)
{
    FileIstream *file = istream_to_file(istream);
    int fd = file->fd;

    evtimer_del(&file->event);
    istream_deinit(&file->stream);

    return fd;
}

static void
istream_file_close(struct istream *istream)
{
    FileIstream *file = istream_to_file(istream);

    file->CloseHandle();

    istream_deinit(&file->stream);
}

static const struct istream_class istream_file = {
    .available = istream_file_available,
    .skip = istream_file_skip,
    .read = istream_file_read,
    .as_fd = istream_file_as_fd,
    .close = istream_file_close,
};

/*
 * constructor and public methods
 *
 */

struct istream *
istream_file_fd_new(struct pool *pool, const char *path,
                    int fd, FdType fd_type, off_t length)
{
    assert(fd >= 0);
    assert(length >= -1);

    auto file = NewFromPool<FileIstream>(*pool);
    istream_init(&file->stream, &istream_file, pool);
    file->fd = fd;
    file->fd_type = fd_type;
    file->rest = length;
    file->buffer.SetNull();
    file->path = path;

    evtimer_set(&file->event, file_event_callback, file);

    return &file->stream;
}

struct istream *
istream_file_stat_new(struct pool *pool, const char *path, struct stat *st,
                      GError **error_r)
{
    assert(path != nullptr);
    assert(st != nullptr);

    int fd = open_cloexec(path, O_RDONLY|O_NOCTTY, 0);
    if (fd < 0) {
        set_error_errno(error_r);
        g_prefix_error(error_r, "Failed to open %s: ", path);
        return nullptr;
    }

    if (fstat(fd, st) < 0) {
        set_error_errno(error_r);
        g_prefix_error(error_r, "Failed to stat %s: ", path);
        close(fd);
        return nullptr;
    }

    FdType fd_type = FdType::FD_FILE;
    off_t size = st->st_size;

    if (S_ISCHR(st->st_mode)) {
        fd_type = FdType::FD_CHARDEV;
        size = -1;
    }

    return istream_file_fd_new(pool, path, fd, fd_type, size);
}

struct istream *
istream_file_new(struct pool *pool, const char *path, off_t length,
                 GError **error_r)
{
    assert(length >= -1);

    int fd = open_cloexec(path, O_RDONLY|O_NOCTTY, 0);
    if (fd < 0) {
        set_error_errno(error_r);
        g_prefix_error(error_r, "Failed to open %s: ", path);
        return nullptr;
    }

    return istream_file_fd_new(pool, path, fd, FdType::FD_FILE, length);
}

int
istream_file_fd(struct istream *istream)
{
    assert(istream != nullptr);
    assert(istream->cls == &istream_file);

    FileIstream *file = istream_to_file(istream);

    assert(file->fd >= 0);

    return file->fd;
}

bool
istream_file_set_range(struct istream *istream, off_t start, off_t end)
{
    assert(istream != nullptr);
    assert(istream->cls == &istream_file);
    assert(start >= 0);
    assert(end >= start);

    FileIstream *file = istream_to_file(istream);
    assert(file->fd >= 0);
    assert(file->rest >= 0);
    assert(file->buffer.IsNull());
    assert(end <= file->rest);

    if (start > 0 && lseek(file->fd, start, SEEK_CUR) < 0)
        return false;

    file->rest = end - start;
    return true;
}
<commit_msg>istream_file: use class Event<commit_after>/*
 * Asynchronous local file access.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "istream_file.hxx"
#include "istream_buffer.hxx"
#include "buffered_io.hxx"
#include "system/fd_util.h"
#include "gerrno.h"
#include "pool.hxx"
#include "fb_pool.hxx"
#include "SliceFifoBuffer.hxx"
#include "event/Event.hxx"
#include "util/Cast.hxx"

#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <limits.h>

/**
 * If EAGAIN occurs (on NFS), we try again after 100ms.  We can't
 * check EV_READ, because the kernel always indicates VFS files as
 * "readable without blocking".
 */
static const struct timeval file_retry_timeout = {
    .tv_sec = 0,
    .tv_usec = 100000,
};

struct FileIstream {
    struct istream stream;
    int fd;

    FdType fd_type;

    /**
     * A timer to retry reading after EAGAIN.
     */
    Event event;

    off_t rest;
    SliceFifoBuffer buffer;
    const char *path;

    void CloseHandle() {
        if (fd < 0)
            return;

        event.Delete();

        close(fd);
        fd = -1;

        buffer.FreeIfDefined(fb_pool_get());
    }

    void Abort(GError *error) {
        CloseHandle();

        istream_deinit_abort(&stream, error);
    }

    /**
     * @return the number of bytes still in the buffer
     */
    size_t SubmitBuffer() {
        return istream_buffer_consume(&stream, buffer);
    }

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

        CloseHandle();
        istream_deinit_eof(&stream);
    }

    gcc_pure
    size_t GetMaxRead() const {
        if (rest != (off_t)-1 && rest < (off_t)INT_MAX)
            return (size_t)rest;
        else
            return INT_MAX;
    }

    void TryData();
    void TryDirect();

    void TryRead() {
        if (istream_check_direct(&stream, fd_type))
            TryDirect();
        else
            TryData();
    }
};

inline void
FileIstream::TryData()
{
    size_t buffer_rest = 0;

    if (buffer.IsNull()) {
        if (rest != 0)
            buffer.Allocate(fb_pool_get());
    } else {
        const size_t available = buffer.GetAvailable();
        if (available > 0) {
            buffer_rest = SubmitBuffer();
            if (buffer_rest == available)
                /* not a single byte was consumed: we may have been
                   closed, and we must bail out now */
                return;
        }
    }

    if (rest == 0) {
        if (buffer_rest == 0)
            EofDetected();
        return;
    }

    ssize_t nbytes = read_to_buffer(fd, buffer, GetMaxRead());
    if (nbytes == 0) {
        if (rest == (off_t)-1) {
            rest = 0;
            if (buffer_rest == 0)
                EofDetected();
        } else {
            GError *error =
                g_error_new(g_file_error_quark(), 0,
                            "premature end of file in '%s'", path);
            Abort(error);
        }
        return;
    } else if (nbytes == -1) {
        GError *error =
            g_error_new(errno_quark(), errno,
                        "failed to read from '%s': %s",
                        path, strerror(errno));
        Abort(error);
        return;
    } else if (nbytes > 0 && rest != (off_t)-1) {
        rest -= (off_t)nbytes;
        assert(rest >= 0);
    }

    assert(!buffer.IsEmpty());

    buffer_rest = SubmitBuffer();
    if (buffer_rest == 0 && rest == 0)
        EofDetected();
}

inline void
FileIstream::TryDirect()
{
    assert(stream.handler->direct != nullptr);

    /* first consume the rest of the buffer */
    if (SubmitBuffer() > 0)
        return;

    if (rest == 0) {
        EofDetected();
        return;
    }

    ssize_t nbytes = istream_invoke_direct(&stream,
                                           fd_type, fd,
                                           GetMaxRead());
    if (nbytes == ISTREAM_RESULT_CLOSED)
        /* this stream was closed during the direct() callback */
        return;

    if (nbytes > 0 || nbytes == ISTREAM_RESULT_BLOCKING) {
        /* -2 means the callback wasn't able to consume any data right
           now */
        if (nbytes > 0 && rest != (off_t)-1) {
            rest -= (off_t)nbytes;
            assert(rest >= 0);
            if (rest == 0)
                EofDetected();
        }
    } else if (nbytes == ISTREAM_RESULT_EOF) {
        if (rest == (off_t)-1) {
            EofDetected();
        } else {
            GError *error =
                g_error_new(g_file_error_quark(), 0,
                            "premature end of file in '%s'", path);
            Abort(error);
        }
    } else if (errno == EAGAIN) {
        /* this should only happen for splice(SPLICE_F_NONBLOCK) from
           NFS files - unfortunately we cannot use EV_READ here, so we
           just install a timer which retries after 100ms */

        event.Add(file_retry_timeout);
    } else {
        /* XXX */
        GError *error =
            g_error_new(errno_quark(), errno,
                        "failed to read from '%s': %s",
                        path, strerror(errno));
        Abort(error);
    }
}

static void
file_event_callback(gcc_unused int fd, gcc_unused short event,
                    void *ctx)
{
    FileIstream *file = (FileIstream *)ctx;

    file->TryRead();
}

/*
 * istream implementation
 *
 */

static inline FileIstream *
istream_to_file(struct istream *istream)
{
    return &ContainerCast2(*istream, &FileIstream::stream);
}

static off_t
istream_file_available(struct istream *istream, bool partial)
{
    FileIstream *file = istream_to_file(istream);
    off_t available = 0;

    if (file->rest != (off_t)-1)
        available = file->rest;
    else if (!partial)
        return (off_t)-1;
    else
        available = 0;

    available += file->buffer.GetAvailable();
    return available;
}

static off_t
istream_file_skip(struct istream *istream, off_t length)
{
    FileIstream *file = istream_to_file(istream);

    file->event.Delete();

    if (file->rest == (off_t)-1)
        return (off_t)-1;

    if (length == 0)
        return 0;

    /* clear the buffer; later we could optimize this function by
       flushing only the skipped number of bytes */
    file->buffer.Clear();

    if (length >= file->rest) {
        /* skip beyond EOF */

        length = file->rest;
        file->rest = 0;
    } else {
        /* seek the file descriptor */

        off_t ret = lseek(file->fd, length, SEEK_CUR);
        if (ret < 0)
            return -1;
        file->rest -= length;
    }

    return length;
}

static void
istream_file_read(struct istream *istream)
{
    FileIstream *file = istream_to_file(istream);

    assert(file->stream.handler != nullptr);

    file->event.Delete();

    file->TryRead();
}

static int
istream_file_as_fd(struct istream *istream)
{
    FileIstream *file = istream_to_file(istream);
    int fd = file->fd;

    file->event.Delete();
    istream_deinit(&file->stream);

    return fd;
}

static void
istream_file_close(struct istream *istream)
{
    FileIstream *file = istream_to_file(istream);

    file->CloseHandle();

    istream_deinit(&file->stream);
}

static const struct istream_class istream_file = {
    .available = istream_file_available,
    .skip = istream_file_skip,
    .read = istream_file_read,
    .as_fd = istream_file_as_fd,
    .close = istream_file_close,
};

/*
 * constructor and public methods
 *
 */

struct istream *
istream_file_fd_new(struct pool *pool, const char *path,
                    int fd, FdType fd_type, off_t length)
{
    assert(fd >= 0);
    assert(length >= -1);

    auto file = NewFromPool<FileIstream>(*pool);
    istream_init(&file->stream, &istream_file, pool);
    file->fd = fd;
    file->fd_type = fd_type;
    file->rest = length;
    file->buffer.SetNull();
    file->path = path;

    file->event.SetTimer(file_event_callback, file);

    return &file->stream;
}

struct istream *
istream_file_stat_new(struct pool *pool, const char *path, struct stat *st,
                      GError **error_r)
{
    assert(path != nullptr);
    assert(st != nullptr);

    int fd = open_cloexec(path, O_RDONLY|O_NOCTTY, 0);
    if (fd < 0) {
        set_error_errno(error_r);
        g_prefix_error(error_r, "Failed to open %s: ", path);
        return nullptr;
    }

    if (fstat(fd, st) < 0) {
        set_error_errno(error_r);
        g_prefix_error(error_r, "Failed to stat %s: ", path);
        close(fd);
        return nullptr;
    }

    FdType fd_type = FdType::FD_FILE;
    off_t size = st->st_size;

    if (S_ISCHR(st->st_mode)) {
        fd_type = FdType::FD_CHARDEV;
        size = -1;
    }

    return istream_file_fd_new(pool, path, fd, fd_type, size);
}

struct istream *
istream_file_new(struct pool *pool, const char *path, off_t length,
                 GError **error_r)
{
    assert(length >= -1);

    int fd = open_cloexec(path, O_RDONLY|O_NOCTTY, 0);
    if (fd < 0) {
        set_error_errno(error_r);
        g_prefix_error(error_r, "Failed to open %s: ", path);
        return nullptr;
    }

    return istream_file_fd_new(pool, path, fd, FdType::FD_FILE, length);
}

int
istream_file_fd(struct istream *istream)
{
    assert(istream != nullptr);
    assert(istream->cls == &istream_file);

    FileIstream *file = istream_to_file(istream);

    assert(file->fd >= 0);

    return file->fd;
}

bool
istream_file_set_range(struct istream *istream, off_t start, off_t end)
{
    assert(istream != nullptr);
    assert(istream->cls == &istream_file);
    assert(start >= 0);
    assert(end >= start);

    FileIstream *file = istream_to_file(istream);
    assert(file->fd >= 0);
    assert(file->rest >= 0);
    assert(file->buffer.IsNull());
    assert(end <= file->rest);

    if (start > 0 && lseek(file->fd, start, SEEK_CUR) < 0)
        return false;

    file->rest = end - start;
    return true;
}
<|endoftext|>


<commit_before>#include "VSwellingUr.h"

#include "SymmTensor.h"

/*////////////////////////////////
 *
 *note that this override of modifyStrain is for STRAIN RATE INCREMENTS
 *
 *//////////////////////////////

template<>
InputParameters validParams<VSwellingUr>()
{
  InputParameters params = validParams<VolumetricModel>();
  params.addCoupledVar("burnup", 0, "Coupled Burnup");
  params.addCoupledVar("temp", 0, "Coupled Temperature");
  params.addCoupledVar("porosity", 0.1, "Coupled porosity");
  params.addParam<PostprocessorName>("contact_pressure", 0, "Postpressor for contact_pressure average");
  params.addParam<Real>("total_densification",0.034, "The total fractional densification that can occur");
  params.addParam<Real>("burnup_constant",0.006, "Constant that divides burnup in Densifcation equation in units of FIMA");
  params.addParam<Real>("solid_factor", 0.417, "Factor multiplied against Burnup [FIMA] to determine swelling due to solid fission products");
  params.addParam<bool>("calculate_gas_swelling", true, "Flag to calculate gas swelling");
  params.addParam<bool>("save_solid_swell", false, "Should the solid swelling be saved in a material property");
  params.addParam<bool>("save_densification", false, "Should the densification be saved in a material property");

  return params;
}

VSwellingUr::VSwellingUr( const std::string & name, InputParameters parameters)
  :VolumetricModel( name, parameters ),

   _burnup(coupledValue("burnup")),
   _burnup_old(coupledValueOld("burnup")),

   _temperature(coupledValue("temp")),
   _porosity(coupledValue("porosity")),

   _contact_pressure(getPostprocessorValue("contact_pressure")),

   _total_densification(parameters.get<Real>("total_densification")),
   _burnup_constant(parameters.get<Real>("burnup_constant")),
   _solid_factor(parameters.get<Real>("solid_factor")),
   _calc_gas_swell(parameters.get<bool>("calculate_gas_swelling")),

   _solid_swelling(NULL),
   _gas_swelling(NULL),
   _densification(NULL),

   _solid_swelling_old(NULL),
   _gas_swelling_old(NULL),
   _densification_old(NULL)

{
  if (parameters.get<bool>("save_solid_swell"))
  {
    _solid_swelling = &declareProperty<Real>("solid_swell");
    _solid_swelling_old = &declarePropertyOld<Real>("solid_swell");
  }
  // if ( _calc_gas_swell )
  {
    _gas_swelling = &declareProperty<Real>("gas_swelling");
    _gas_swelling_old = &declarePropertyOld<Real>("gas_swelling");
  }
  if (parameters.get<bool>("save_densification"))
  {
    _densification = &declareProperty<Real>("densification");
    _densification_old = &declarePropertyOld<Real>("densification");
  }
}

////////////////////////////////////////////////////////////////////////

void
VSwellingUr::initStatefulProperties(unsigned n_points)
{
  for (unsigned qp(0); qp < n_points; ++qp)
  {
    if (_solid_swelling)
      (*_solid_swelling)[qp] = 0.;
    if (_solid_swelling_old)
      (*_solid_swelling_old)[qp] = 0.;

    if (_gas_swelling)
      (*_gas_swelling)[qp] = 0.;
    if (_gas_swelling_old)
      (*_gas_swelling_old)[qp] = 0.;

    if (_densification)
      (*_densification)[qp] = 0.;
    if (_densification_old)
      (*_densification_old)[qp] = 0.;
  }
}

void
VSwellingUr::modifyStrain(const unsigned int qp,
                           const Real v0OverVOld,
                           SymmTensor & strain_increment,
                           SymmTensor & dstrain_increment_dT)
{
  if ( _t_step != 0 )
  {
    // Determinant of deformation gradient is current volume over original volume:
    // det(F) = V/V0
    // If F0 is the diagonal value of F for volumetric strain,
    // det(F) = F0^3
    // F0^3 = V/V0
    // F0 = (V/V0)^(1/3) = ((V0+dV)/V0)^(1/3) = (1+dV/V0)^(1/3)
    // Therefore, the volumetric strain increment is
    // F0_n - F0_(n-1)
    //

    // Solid swelling
    Real ssStrainOld(0);
    Real ssStrain(0);
    Real dssStrain_dTOld(0);
    Real dssStrain_dT(0);
    solidSwelling( _solid_factor, _burnup_old[qp], ssStrainOld, dssStrain_dTOld );
    solidSwelling( _solid_factor, _burnup[qp],     ssStrain,    dssStrain_dT );

    if ( _solid_swelling )
    {
      (*_solid_swelling)[qp] = ssStrain;
    }

    Real gsStrainRate(0);
    Real dgsStrainRate_dT(0);
    calcGasSwelling( _burnup[qp], _burnup_old[qp], _temperature[qp], _porosity[qp], _contact_pressure, gsStrainRate, dgsStrainRate_dT );
    if ( _calc_gas_swell )
    {
      (*_gas_swelling)[qp] =  (*_gas_swelling_old)[qp] + gsStrainRate;
    }

    // Densification
    Real dStrainOld(0);
    Real dStrain(0);
    Real ddStrain_dTOld(0);
    Real ddStrain_dT(0);
    densification( _total_densification, _burnup_constant, _burnup_old[qp], dStrainOld, ddStrain_dTOld );
    densification( _total_densification, _burnup_constant, _burnup[qp],     dStrain,    ddStrain_dT );
    if ( _densification )
    {
      (*_densification)[qp] = dStrain;
    }

    // Volumetric strain increments
    const Real oneThird = 1./3.;
    const Real VStrain = std::pow((ssStrain + (*_gas_swelling)[qp] / v0OverVOld + dStrain + 1)*v0OverVOld, oneThird) - \
                         std::pow((ssStrainOld + (*_gas_swelling_old)[qp] / v0OverVOld + dStrainOld + 1)*v0OverVOld, oneThird);
    const Real dVStrain_dT = (dssStrain_dT - dssStrain_dTOld) + dgsStrainRate_dT + (ddStrain_dT  - ddStrain_dTOld);

    strain_increment.addDiag( -VStrain );
    dstrain_increment_dT.addDiag( -dVStrain_dT/3 * v0OverVOld );
    // std::cout << "step: " << _t_step << " strain: " << gsStrainRate << " v0OverVOld: " << v0OverVOld << " contact_pressure: " << _contact_pressure << std::endl;
  }
}

//////////////////////////////////////////////////////////////////////////////////////

void
VSwellingUr::solidSwelling( const Real solid_swelling_factor,
                            const Real burnup,
                            Real & fract_volumetric,
                            Real & dfract_volumetric_dtemp )
{
  // This function computes the solid fission product swelling in UC according to:
  // Matzke: Science of Advanced LMFBR Fuels, pg 466
  //
  // dV/V = 0.5 * Bu (FIMA)

  fract_volumetric = solid_swelling_factor * burnup;
  dfract_volumetric_dtemp = 0.;
}

//////////////////////////////////////////////////////////////////////////////////////

void
VSwellingUr::calcGasSwelling( const Real burnup,
                              const Real burnup_old,
                              const Real temperature,
                              const Real por,
                              const Real cont_pres,
                              Real & fract_volumetric,
                              Real & dfract_volumetric_dtemp )
{
  const Real temp = temperature - 273;
  const Real c( 1.711 );
  const Real d1( 6.412 );
  const Real d2( -0.0198 );
  const Real d3( 0.152e-4 );
  const Real BU0( .0112 ); // [FIMA] from 1 MWd/kg = .00112 FIMA
  const Real a( 2 );
  const Real b( 0.1 );
  const Real pc0( 1e6 ); //[Pa]

  const Real limit( 4.091 ); //4.558 - 0.4667 ( total minus solid swelling )

  Real corr_por = std::exp( - (por - 0.04));
  if ( corr_por > 1 )
    corr_por = 1;

  Real corr_stress = std::exp( - cont_pres / pc0 * b );
  if ( corr_stress > 1 )
    corr_stress = 1;

  Real corr_burnup = burnup / BU0 - a;
  if ( corr_burnup < 0 )
    corr_burnup = 0;

  Real corr_temp = 0;
  Real dcorr_temp = 0;
  if ( temp >= 700 )
  {
    corr_temp = d1 + d2 * temp + d3 * temp * temp;
    dcorr_temp = d2 + d3 * temp;
  }

  fract_volumetric = ( c + corr_temp * corr_burnup ) * corr_por * corr_stress;
  dfract_volumetric_dtemp = dcorr_temp * corr_burnup * corr_por * corr_stress;

  if ( fract_volumetric > limit )
    fract_volumetric = limit;
  if ( fract_volumetric < 0 )
    fract_volumetric = 0;

  const Real burnup_inc = burnup - burnup_old;
  fract_volumetric *= 1.12 * burnup_inc; // convert from [% vol/(MWd/kg)] to [/]
  dfract_volumetric_dtemp *= 1.12 * burnup_inc;
}

//////////////////////////////////////////////////////////////////////////////////////

void
VSwellingUr::densification( const Real total_densification,
                            const Real burnup_constant,
                            const Real burnup,
                            Real & fract_volumetric,
                            Real & dfract_volumetric_dtemp )
{
  // Taken from W. Dienst, JNM 124 (1984) 153-158
  // densification porosity: p = p_total * (1 - exp( -burnup / 0.6 at% ) )

  fract_volumetric = - total_densification * ( 1 - exp( - burnup / burnup_constant ) );
  dfract_volumetric_dtemp = 0;
}
<commit_msg>VSwellingUR fix again<commit_after>#include "VSwellingUr.h"

#include "SymmTensor.h"

/*////////////////////////////////
 *
 *note that this override of modifyStrain is for STRAIN RATE INCREMENTS
 *
 *//////////////////////////////

template<>
InputParameters validParams<VSwellingUr>()
{
  InputParameters params = validParams<VolumetricModel>();
  params.addCoupledVar("burnup", 0, "Coupled Burnup");
  params.addCoupledVar("temp", 0, "Coupled Temperature");
  params.addCoupledVar("porosity", 0.1, "Coupled porosity");
  params.addParam<PostprocessorName>("contact_pressure", 0, "Postpressor for contact_pressure average");
  params.addParam<Real>("total_densification",0.034, "The total fractional densification that can occur");
  params.addParam<Real>("burnup_constant",0.006, "Constant that divides burnup in Densifcation equation in units of FIMA");
  params.addParam<Real>("solid_factor", 0.417, "Factor multiplied against Burnup [FIMA] to determine swelling due to solid fission products");
  params.addParam<bool>("calculate_gas_swelling", true, "Flag to calculate gas swelling");
  params.addParam<bool>("save_solid_swell", false, "Should the solid swelling be saved in a material property");
  params.addParam<bool>("save_densification", false, "Should the densification be saved in a material property");

  return params;
}

VSwellingUr::VSwellingUr( const std::string & name, InputParameters parameters)
  :VolumetricModel( name, parameters ),

   _burnup(coupledValue("burnup")),
   _burnup_old(coupledValueOld("burnup")),

   _temperature(coupledValue("temp")),
   _porosity(coupledValue("porosity")),

   _contact_pressure(getPostprocessorValue("contact_pressure")),

   _total_densification(parameters.get<Real>("total_densification")),
   _burnup_constant(parameters.get<Real>("burnup_constant")),
   _solid_factor(parameters.get<Real>("solid_factor")),
   _calc_gas_swell(parameters.get<bool>("calculate_gas_swelling")),

   _solid_swelling(NULL),
   _gas_swelling(NULL),
   _densification(NULL),

   _solid_swelling_old(NULL),
   _gas_swelling_old(NULL),
   _densification_old(NULL)

{
  if (parameters.get<bool>("save_solid_swell"))
  {
    _solid_swelling = &declareProperty<Real>("solid_swell");
    _solid_swelling_old = &declarePropertyOld<Real>("solid_swell");
  }
  // if ( _calc_gas_swell )
  {
    _gas_swelling = &declareProperty<Real>("gas_swelling");
    _gas_swelling_old = &declarePropertyOld<Real>("gas_swelling");
  }
  if (parameters.get<bool>("save_densification"))
  {
    _densification = &declareProperty<Real>("densification");
    _densification_old = &declarePropertyOld<Real>("densification");
  }
}

////////////////////////////////////////////////////////////////////////

void
VSwellingUr::initStatefulProperties(unsigned n_points)
{
  for (unsigned qp(0); qp < n_points; ++qp)
  {
    if (_solid_swelling)
      (*_solid_swelling)[qp] = 0.;
    if (_solid_swelling_old)
      (*_solid_swelling_old)[qp] = 0.;

    if (_gas_swelling)
      (*_gas_swelling)[qp] = 0.;
    if (_gas_swelling_old)
      (*_gas_swelling_old)[qp] = 0.;

    if (_densification)
      (*_densification)[qp] = 0.;
    if (_densification_old)
      (*_densification_old)[qp] = 0.;
  }
}

void
VSwellingUr::modifyStrain(const unsigned int qp,
                           const Real v0OverVOld,
                           SymmTensor & strain_increment,
                           SymmTensor & dstrain_increment_dT)
{
  if ( _t_step != 0 )
  {
    // Determinant of deformation gradient is current volume over original volume:
    // det(F) = V/V0
    // If F0 is the diagonal value of F for volumetric strain,
    // det(F) = F0^3
    // F0^3 = V/V0
    // F0 = (V/V0)^(1/3) = ((V0+dV)/V0)^(1/3) = (1+dV/V0)^(1/3)
    // Therefore, the volumetric strain increment is
    // F0_n - F0_(n-1)
    //

    // Solid swelling
    Real ssStrainOld(0);
    Real ssStrain(0);
    Real dssStrain_dTOld(0);
    Real dssStrain_dT(0);
    solidSwelling( _solid_factor, _burnup_old[qp], ssStrainOld, dssStrain_dTOld );
    solidSwelling( _solid_factor, _burnup[qp],     ssStrain,    dssStrain_dT );

    if ( _solid_swelling )
    {
      (*_solid_swelling)[qp] = ssStrain;
    }

    Real gsStrainRate(0);
    Real dgsStrainRate_dT(0);
    calcGasSwelling( _burnup[qp], _burnup_old[qp], _temperature[qp], _porosity[qp], _contact_pressure, gsStrainRate, dgsStrainRate_dT );
    if ( _calc_gas_swell )
    {
      (*_gas_swelling)[qp] =  (*_gas_swelling_old)[qp] + gsStrainRate;
    }

    // Densification
    Real dStrainOld(0);
    Real dStrain(0);
    Real ddStrain_dTOld(0);
    Real ddStrain_dT(0);
    densification( _total_densification, _burnup_constant, _burnup_old[qp], dStrainOld, ddStrain_dTOld );
    densification( _total_densification, _burnup_constant, _burnup[qp],     dStrain,    ddStrain_dT );
    if ( _densification )
    {
      (*_densification)[qp] = dStrain;
    }

    // Volumetric strain increments
    const Real oneThird = 1./3.;
    const Real VStrain = std::pow((ssStrain + (*_gas_swelling)[qp] / v0OverVOld + dStrain + 1)*v0OverVOld, oneThird) - \
                         std::pow((ssStrainOld + (*_gas_swelling_old)[qp] / v0OverVOld + dStrainOld + 1)*v0OverVOld, oneThird);
    const Real dVStrain_dT = (dssStrain_dT - dssStrain_dTOld) + dgsStrainRate_dT + (ddStrain_dT  - ddStrain_dTOld);

    strain_increment.addDiag( -VStrain );
    dstrain_increment_dT.addDiag( -dVStrain_dT/3 * v0OverVOld );
    // std::cout << "step: " << _t_step << " strain: " << gsStrainRate << " v0OverVOld: " << v0OverVOld << " contact_pressure: " << _contact_pressure << std::endl;
  }
}

//////////////////////////////////////////////////////////////////////////////////////

void
VSwellingUr::solidSwelling( const Real solid_swelling_factor,
                            const Real burnup,
                            Real & fract_volumetric,
                            Real & dfract_volumetric_dtemp )
{
  // This function computes the solid fission product swelling in UC according to:
  // Matzke: Science of Advanced LMFBR Fuels, pg 466
  //
  // dV/V = 0.5 * Bu (FIMA)

  fract_volumetric = solid_swelling_factor * burnup;
  dfract_volumetric_dtemp = 0.;
}

//////////////////////////////////////////////////////////////////////////////////////

void
VSwellingUr::calcGasSwelling( const Real burnup,
                              const Real burnup_old,
                              const Real temperature,
                              const Real por,
                              const Real cont_pres,
                              Real & fract_volumetric,
                              Real & dfract_volumetric_dtemp )
{
  const Real temp = temperature - 273;
  const Real c( 1.711 );
  const Real d1( 6.412 );
  const Real d2( -0.0198 );
  const Real d3( 0.152e-4 );
  const Real BU0( .0112 ); // [FIMA] from 1 MWd/kg = .00112 FIMA
  const Real a( 2 );
  const Real b( 0.1 );
  const Real pc0( 1e6 ); //[Pa]

  const Real limit( 4.091 ); //4.558 - 0.4667 ( total minus solid swelling )

  Real corr_por = std::exp( - (por - 0.04));
  if ( corr_por > 1 )
    corr_por = 1;

  Real corr_stress = std::exp( - cont_pres / pc0 * b );
  if ( corr_stress > 1 )
    corr_stress = 1;

  Real corr_burnup = burnup / BU0 - a;
  if ( corr_burnup < 0 )
    corr_burnup = 0;

  Real corr_temp = 0;
  Real dcorr_temp = 0;
  if ( temp >= 700 )
  {
    corr_temp = d1 + d2 * temp + d3 * temp * temp;
    dcorr_temp = d2 + d3 * temp;
  }

  fract_volumetric = ( c + corr_temp * corr_burnup ) * corr_por * corr_stress;
  dfract_volumetric_dtemp = dcorr_temp * corr_burnup * corr_por * corr_stress;

  if ( fract_volumetric > limit )
  {
    fract_volumetric = limit;
    dfract_volumetric_dtemp = 0; // I think?
  }
  if ( fract_volumetric < 0 )
    fract_volumetric = 0;

  const Real burnup_inc = burnup - burnup_old;
  fract_volumetric *= 1.12 * burnup_inc; // convert from [% vol/(MWd/kg)] to [/]
  dfract_volumetric_dtemp *= 1.12 * burnup_inc;
}

//////////////////////////////////////////////////////////////////////////////////////

void
VSwellingUr::densification( const Real total_densification,
                            const Real burnup_constant,
                            const Real burnup,
                            Real & fract_volumetric,
                            Real & dfract_volumetric_dtemp )
{
  // Taken from W. Dienst, JNM 124 (1984) 153-158
  // densification porosity: p = p_total * (1 - exp( -burnup / 0.6 at% ) )

  fract_volumetric = - total_densification * ( 1 - exp( - burnup / burnup_constant ) );
  dfract_volumetric_dtemp = 0;
}
<|endoftext|>


<commit_before>// exposes the glob function to node.

// int
// glob(const char *restrict pattern, int flags,
//     int (*errfunc)(const char *epath, int errno), glob_t *restrict pglob);

#include <v8.h>
#include <glob.h>
#include <node.h>
#include <string.h>

using namespace std;
using namespace node;
using namespace v8;

#include "glob_constants.h"

static Handle<String>
GlobError (int er) {
  switch (er) {
    case GLOB_ABORTED: return String::New("GLOB_ABORTED"); break;
    case GLOB_NOMATCH: return String::New("GLOB_NOMATCH"); break;
    case GLOB_NOSPACE: return String::New("GLOB_NOSPACE"); break;
  }

  return String::New("undefined glob error");
}

static Handle<Value> Throw (int);
static Handle<Value> Throw (const char*);
static Handle<Value> Throw (Handle<String>);

static Handle<Value>
Throw (int msg) {
  return Throw(GlobError(msg));
}
static Handle<Value>
Throw (const char* msg) {
  return Throw(String::New(msg));
}
static Handle<Value>
Throw (Handle<String> msg) {
  ThrowException(Exception::Error(msg));
}

// async EIO globbing
struct glob_request {
  Persistent<Function> cb;
  glob_t *g;
  int retval;
  int flags;
  char pattern[1];
};
static int EIO_Glob (eio_req *req) {
  glob_request *gr = (glob_request *)req->data;
  gr->retval = glob(gr->pattern, gr->flags, NULL, gr->g);
  return 0;
}
static int EIO_GlobAfter (eio_req *req) {
  HandleScope scope;
  ev_unref(EV_DEFAULT_UC);
  glob_request *gr = (glob_request *)req->data;
  glob_t *g = gr->g;

  Local<Value> argv[2];
  if (gr->retval != 0) {
    argv[0] = Exception::Error(GlobError(gr->retval));
    argv[1] = String::New(gr->pattern);
  } else {
    Local<Array> pathv = Array::New(g->gl_pathc);
    for (int i = 0; i < g->gl_pathc; i ++) {
      pathv->Set(Integer::New(i), String::New(g->gl_pathv[i]));
    }
    argv[0] = Local<Value>::New(Null());
    argv[1] = pathv;
  }

  TryCatch try_catch;
  gr->cb->Call(Context::GetCurrent()->Global(), 2, argv);
  if (try_catch.HasCaught()) {
    FatalException(try_catch);
  }
  // fprintf(stderr, "EIO_GlobAfter about to free\n");
  gr->cb.Dispose();
  globfree(g);
  free(gr);
  // fprintf(stderr, "EIO_GlobAfter freed\n");
  return 0;
}
static Handle<Value> GlobAsync (const Arguments& args) {
  HandleScope scope;
  const char *usage = "usage: glob(pattern, flags, cb)";

  if (args.Length() != 3) {
    Throw(usage);
  }

  String::Utf8Value pattern(args[0]);

  int flags = args[1]->Int32Value();
  Local<Function> cb = Local<Function>::Cast(args[2]);

  glob_request *gr = (glob_request *)
    calloc(1, sizeof(struct glob_request) + pattern.length() + 1);

  gr->cb = Persistent<Function>::New(cb);
  strncpy(gr->pattern, *pattern, pattern.length() + 1);
  gr->flags = flags;
  gr->g = new glob_t;
  eio_custom(EIO_Glob, EIO_PRI_DEFAULT, EIO_GlobAfter, gr);
  ev_ref(EV_DEFAULT_UC);

  return Undefined();
}

// synchronous globbing.
static Handle<Value> GlobSync (const Arguments& args) {
  HandleScope scope;
  const char * usage = "usage: globSync(pattern, flags)";
  if (args.Length() != 2) {
    return Throw(usage);
  }

  String::Utf8Value pattern(args[0]);

  int flags = args[1]->Int32Value();

  glob_t g;
  int retval = glob(*pattern, flags, NULL, &g);

  if (retval != 0) {
    globfree(&g);
    return Throw(retval);
  }

  // create a JS array
  // loop through the g.gl_pathv adding JS strings to the JS array.
  // then return the JS array.
  Handle<Array> pathv = Array::New(g.gl_pathc);
  for (int i = 0; i < g.gl_pathc; i ++) {
    pathv->Set(Integer::New(i), String::New(g.gl_pathv[i]));
  }

  globfree(&g);
  return scope.Close(pathv);
}

extern "C" void
init (Handle<Object> target)
{
  HandleScope scope;
  GlobConstants(target);
  NODE_SET_METHOD(target, "glob", GlobAsync);
  NODE_SET_METHOD(target, "globSync", GlobSync);
}

<commit_msg>Make the error sniffing safe and portable<commit_after>// exposes the glob function to node.

// int
// glob(const char *restrict pattern, int flags,
//     int (*errfunc)(const char *epath, int errno), glob_t *restrict pglob);

#include <v8.h>
#include <glob.h>
#include <node.h>
#include <string.h>

using namespace std;
using namespace node;
using namespace v8;

#include "glob_constants.h"

static Handle<String>
GlobError (int er) {
  switch (er) {
#ifdef GLOB_ABORTED
    case GLOB_ABORTED: return String::New("GLOB_ABORTED"); break;
#endif
#ifdef GLOB_ABEND
    case GLOB_ABEND: return String::New("GLOB_ABEND"); break;
#endif
#ifdef GLOB_NOMATCH
    case GLOB_NOMATCH: return String::New("GLOB_NOMATCH"); break;
#endif
#ifdef GLOB_NOSPACE
    case GLOB_NOSPACE: return String::New("GLOB_NOSPACE"); break;
#endif
  }

  return String::New("undefined glob error");
}

static Handle<Value> Throw (int);
static Handle<Value> Throw (const char*);
static Handle<Value> Throw (Handle<String>);

static Handle<Value>
Throw (int msg) {
  return Throw(GlobError(msg));
}
static Handle<Value>
Throw (const char* msg) {
  return Throw(String::New(msg));
}
static Handle<Value>
Throw (Handle<String> msg) {
  ThrowException(Exception::Error(msg));
}

// async EIO globbing
struct glob_request {
  Persistent<Function> cb;
  glob_t *g;
  int retval;
  int flags;
  char pattern[1];
};
static int EIO_Glob (eio_req *req) {
  glob_request *gr = (glob_request *)req->data;
  gr->retval = glob(gr->pattern, gr->flags, NULL, gr->g);
  return 0;
}
static int EIO_GlobAfter (eio_req *req) {
  HandleScope scope;
  ev_unref(EV_DEFAULT_UC);
  glob_request *gr = (glob_request *)req->data;
  glob_t *g = gr->g;

  Local<Value> argv[2];
  if (gr->retval != 0) {
    argv[0] = Exception::Error(GlobError(gr->retval));
    argv[1] = String::New(gr->pattern);
  } else {
    Local<Array> pathv = Array::New(g->gl_pathc);
    for (int i = 0; i < g->gl_pathc; i ++) {
      pathv->Set(Integer::New(i), String::New(g->gl_pathv[i]));
    }
    argv[0] = Local<Value>::New(Null());
    argv[1] = pathv;
  }

  TryCatch try_catch;
  gr->cb->Call(Context::GetCurrent()->Global(), 2, argv);
  if (try_catch.HasCaught()) {
    FatalException(try_catch);
  }
  // fprintf(stderr, "EIO_GlobAfter about to free\n");
  gr->cb.Dispose();
  globfree(g);
  free(gr);
  // fprintf(stderr, "EIO_GlobAfter freed\n");
  return 0;
}
static Handle<Value> GlobAsync (const Arguments& args) {
  HandleScope scope;
  const char *usage = "usage: glob(pattern, flags, cb)";

  if (args.Length() != 3) {
    Throw(usage);
  }

  String::Utf8Value pattern(args[0]);

  int flags = args[1]->Int32Value();
  Local<Function> cb = Local<Function>::Cast(args[2]);

  glob_request *gr = (glob_request *)
    calloc(1, sizeof(struct glob_request) + pattern.length() + 1);

  gr->cb = Persistent<Function>::New(cb);
  strncpy(gr->pattern, *pattern, pattern.length() + 1);
  gr->flags = flags;
  gr->g = new glob_t;
  eio_custom(EIO_Glob, EIO_PRI_DEFAULT, EIO_GlobAfter, gr);
  ev_ref(EV_DEFAULT_UC);

  return Undefined();
}

// synchronous globbing.
static Handle<Value> GlobSync (const Arguments& args) {
  HandleScope scope;
  const char * usage = "usage: globSync(pattern, flags)";
  if (args.Length() != 2) {
    return Throw(usage);
  }

  String::Utf8Value pattern(args[0]);

  int flags = args[1]->Int32Value();

  glob_t g;
  int retval = glob(*pattern, flags, NULL, &g);

  if (retval != 0) {
    globfree(&g);
    return Throw(retval);
  }

  // create a JS array
  // loop through the g.gl_pathv adding JS strings to the JS array.
  // then return the JS array.
  Handle<Array> pathv = Array::New(g.gl_pathc);
  for (int i = 0; i < g.gl_pathc; i ++) {
    pathv->Set(Integer::New(i), String::New(g.gl_pathv[i]));
  }

  globfree(&g);
  return scope.Close(pathv);
}

extern "C" void
init (Handle<Object> target)
{
  HandleScope scope;
  GlobConstants(target);
  NODE_SET_METHOD(target, "glob", GlobAsync);
  NODE_SET_METHOD(target, "globSync", GlobSync);
}

<|endoftext|>