<commit_before>/*
 * Copyright 2004-present Facebook, Inc.
 *
 * 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 <thrift/lib/cpp2/transport/http2/common/HTTP2RoutingHandler.h>

#include <gflags/gflags.h>
#include <proxygen/httpserver/HTTPServerAcceptor.h>
#include <proxygen/httpserver/HTTPServerOptions.h>
#include <proxygen/httpserver/RequestHandler.h>
#include <proxygen/httpserver/RequestHandlerAdaptor.h>
#include <proxygen/lib/http/codec/HTTPCodec.h>
#include <proxygen/lib/http/codec/HTTPSettings.h>
#include <proxygen/lib/http/session/HTTPDefaultSessionCodecFactory.h>
#include <proxygen/lib/http/session/HTTPDownstreamSession.h>
#include <proxygen/lib/http/session/HTTPSession.h>
#include <proxygen/lib/http/session/SimpleController.h>
#include <thrift/lib/cpp2/transport/http2/common/H2ChannelFactory.h>
#include <thrift/lib/cpp2/transport/http2/server/ThriftRequestHandler.h>
#include <wangle/acceptor/ManagedConnection.h>
#include <limits>

DECLARE_int32(force_channel_version);

namespace apache {
namespace thrift {

namespace {
// Class for managing lifetime of objects supporting an HTTP2 session.
class HTTP2RoutingSessionManager : public proxygen::HTTPSession::InfoCallback,
                                   public proxygen::SimpleController {
 public:
  HTTP2RoutingSessionManager(
      std::unique_ptr<proxygen::HTTPServerAcceptor> acceptor,
      ThriftProcessor* processor)
      : proxygen::HTTPSession::InfoCallback(),
        proxygen::SimpleController(acceptor.get()),
        processor_(processor),
        negotiatedChannelVersion_(FLAGS_force_channel_version) {
    acceptor_ = std::move(acceptor);
    if (FLAGS_force_channel_version > 0) {
      // This prevents the inspection of the HTTP2 header for the channel
      // version.
      stableId_ = 0;
    } else {
      stableId_ = std::numeric_limits<proxygen::HTTPCodec::StreamID>::max();
    }
  }

  ~HTTP2RoutingSessionManager() = default;

  proxygen::HTTPDownstreamSession* createSession(
      folly::AsyncTransportWrapper::UniquePtr sock,
      folly::SocketAddress* peerAddress,
      std::unique_ptr<proxygen::HTTPCodec> h2codec,
      wangle::TransportInfo const& tinfo) {
    // Obtain the proper routing address
    folly::SocketAddress localAddress;
    try {
      sock->getLocalAddress(&localAddress);
    } catch (...) {
      VLOG(3) << "couldn't get local address for socket";
      localAddress = folly::SocketAddress("0.0.0.0", 0);
    }
    VLOG(4) << "Created new session for peer " << *peerAddress;

    // Create the DownstreamSession.  Note that "this" occurs twice
    // because it acts as both a controller as well as a info
    // callback.
    auto session = new proxygen::HTTPDownstreamSession(
        proxygen::WheelTimerInstance(std::chrono::milliseconds(5)),
        std::move(sock),
        localAddress,
        *peerAddress,
        this,
        std::move(h2codec),
        tinfo,
        this);

    return session;
  }

  // begin HTTPSession::InfoCallback methods

  // We do not override onDestroy() to self destroy because this object
  // doubles as both the InfoCallback and the SimpleController.  The
  // session destructor calls onDestroy() first and then detachSession()
  // so we self destroy at detachSession().

  void onSettings(
      const proxygen::HTTPSessionBase&,
      const proxygen::SettingsList& settings) override {
    if (FLAGS_force_channel_version > 0) {
      // Do not use the negotiated settings.
      return;
    }
    for (auto& setting : settings) {
      if (setting.id == kChannelSettingId) {
        negotiatedChannelVersion_ =
            std::min(setting.value, kMaxSupportedChannelVersion);
        VLOG(2) << "Peer channel version is " << setting.value;
        VLOG(2) << "Negotiated channel version is "
                << negotiatedChannelVersion_;
      }
    }
    if (negotiatedChannelVersion_ == 0) {
      // Did not receive a channel version, assuming legacy peer.
      negotiatedChannelVersion_ = 1;
    }
  }

  // end HTTPSession::InfoCallback methods

  // begin SimpleController methods

  proxygen::HTTPTransactionHandler* getRequestHandler(
      proxygen::HTTPTransaction& txn,
      proxygen::HTTPMessage* msg) override {
    folly::SocketAddress clientAddr, vipAddr;
    txn.getPeerAddress(clientAddr);
    txn.getLocalAddress(vipAddr);
    msg->setClientAddress(clientAddr);
    msg->setDstAddress(vipAddr);

    // This checks that the SETTINGS frame arrives before the first RPC.
    DCHECK(negotiatedChannelVersion_ > 0);

    // Determine channel version for this HTTP2 stream.
    uint32_t version = negotiatedChannelVersion_;
    if (UNLIKELY(txn.getID() < stableId_)) {
      auto val = msg->getHeaders().rawGet(kChannelVersionKey);
      try {
        version = folly::to<int>(val);
      } catch (const std::exception& ex) {
        LOG(WARNING) << "Channel version not set properly in header: " << val;
        // This could be from a legacy client.
        version = 1;
      }
      DCHECK(version == 1 || version == negotiatedChannelVersion_);
      if (version == negotiatedChannelVersion_) {
        stableId_ = txn.getID();
      }
    }

    proxygen::RequestHandler* handler =
        new ThriftRequestHandler(processor_, version);
    return new proxygen::RequestHandlerAdaptor(handler);
  }

  void detachSession(const proxygen::HTTPSession*) override {
    VLOG(4) << "HTTP2RoutingSessionManager::detachSession";
    // Session destroyed, so self destroy.
    delete this;
  }

  // end SimpleController methods

 private:
  // Supporting objects for HTTP2 session managed by the callback.
  std::unique_ptr<proxygen::HTTPServerAcceptor> acceptor_;

  ThriftProcessor* processor_;

  // The negotiated channel version - 0 means negotiation has not
  // taken place yet.  Negotiation is completed when the server
  // receives a header with a non-zero channel version.
  uint32_t negotiatedChannelVersion_;

  // The stream id after which the server can assume that the channel
  // version will be the negotiated version.
  proxygen::HTTPCodec::StreamID stableId_;
};

} // anonymous namespace

bool HTTP2RoutingHandler::canAcceptConnection(
    const std::vector<uint8_t>& bytes) {
  /*
   * HTTP/2.0 requests start with the following sequence:
   *   Octal: 0x505249202a20485454502f322e300d0a0d0a534d0d0a0d0a
   *  String: "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
   *
   * For more, see: https://tools.ietf.org/html/rfc7540#section-3.5
   */
  if (bytes[0] == 0x50 && bytes[1] == 0x52 && bytes[2] == 0x49) {
    return true;
  }

  /*
   * HTTP requests start with the following sequence:
   *   Octal: "0x485454502f..."
   *  String: "HTTP/X.X"
   *
   * For more, see: https://tools.ietf.org/html/rfc2616#section-3
   */
  if (bytes[0] == 0x48 && bytes[1] == 0x54 && bytes[2] == 0x54) {
    return true;
  }

  return false;
}

bool HTTP2RoutingHandler::canAcceptEncryptedConnection(
    const std::string& protocolName) {
  return protocolName == "h2" || protocolName == "http";
}

void HTTP2RoutingHandler::handleConnection(
    wangle::ConnectionManager* connectionManager,
    folly::AsyncTransportWrapper::UniquePtr sock,
    folly::SocketAddress* peerAddress,
    wangle::TransportInfo const& tinfo) {
  // Create the DownstreamSession manager.
  auto ipConfig = proxygen::HTTPServer::IPConfig(
      *peerAddress, proxygen::HTTPServer::Protocol::HTTP2);
  auto acceptorConfig =
      proxygen::HTTPServerAcceptor::makeConfig(ipConfig, *options_);
  auto acceptor = proxygen::HTTPServerAcceptor::make(acceptorConfig, *options_);
  auto sessionManager =
      new HTTP2RoutingSessionManager(std::move(acceptor), processor_);
  // Get the HTTP2 Codec
  auto codecFactory = proxygen::HTTPDefaultSessionCodecFactory(acceptorConfig);
  auto h2codec =
      codecFactory.getCodec("h2", proxygen::TransportDirection::DOWNSTREAM);
  // Create the DownstreamSession
  auto session = sessionManager->createSession(
      std::move(sock), peerAddress, std::move(h2codec), tinfo);
  // Set HTTP2 priorities flag on session object.
  session->setHTTP2PrioritiesEnabled(acceptorConfig.HTTP2PrioritiesEnabled);
  /*
  if (acceptorConfig.maxConcurrentIncomingStreams) {
    session->setMaxConcurrentIncomingStreams(
        acceptorConfig.maxConcurrentIncomingStreams);
  }
  */
  // TODO: Improve the way max incoming streams is set
  session->setMaxConcurrentIncomingStreams(100000);

  // Set flow control parameters.
  session->setFlowControl(
      acceptorConfig.initialReceiveWindow,
      acceptorConfig.receiveStreamWindowSize,
      acceptorConfig.receiveSessionWindowSize);
  if (acceptorConfig.writeBufferLimit > 0) {
    session->setWriteBufferLimit(acceptorConfig.writeBufferLimit);
  }
  session->setEgressSettings(
      {{kChannelSettingId, kMaxSupportedChannelVersion}});

  // Route the connection.
  connectionManager->addConnection(session);
  session->startNow();
}

} // namspace thrift
} // namespace apache
<commit_msg>Make HTTPSessionController callbacks take HTTPSessionBase<commit_after>/*
 * Copyright 2004-present Facebook, Inc.
 *
 * 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 <thrift/lib/cpp2/transport/http2/common/HTTP2RoutingHandler.h>

#include <gflags/gflags.h>
#include <proxygen/httpserver/HTTPServerAcceptor.h>
#include <proxygen/httpserver/HTTPServerOptions.h>
#include <proxygen/httpserver/RequestHandler.h>
#include <proxygen/httpserver/RequestHandlerAdaptor.h>
#include <proxygen/lib/http/codec/HTTPCodec.h>
#include <proxygen/lib/http/codec/HTTPSettings.h>
#include <proxygen/lib/http/session/HTTPDefaultSessionCodecFactory.h>
#include <proxygen/lib/http/session/HTTPDownstreamSession.h>
#include <proxygen/lib/http/session/HTTPSession.h>
#include <proxygen/lib/http/session/SimpleController.h>
#include <thrift/lib/cpp2/transport/http2/common/H2ChannelFactory.h>
#include <thrift/lib/cpp2/transport/http2/server/ThriftRequestHandler.h>
#include <wangle/acceptor/ManagedConnection.h>
#include <limits>

DECLARE_int32(force_channel_version);

namespace apache {
namespace thrift {

namespace {
// Class for managing lifetime of objects supporting an HTTP2 session.
class HTTP2RoutingSessionManager : public proxygen::HTTPSession::InfoCallback,
                                   public proxygen::SimpleController {
 public:
  HTTP2RoutingSessionManager(
      std::unique_ptr<proxygen::HTTPServerAcceptor> acceptor,
      ThriftProcessor* processor)
      : proxygen::HTTPSession::InfoCallback(),
        proxygen::SimpleController(acceptor.get()),
        processor_(processor),
        negotiatedChannelVersion_(FLAGS_force_channel_version) {
    acceptor_ = std::move(acceptor);
    if (FLAGS_force_channel_version > 0) {
      // This prevents the inspection of the HTTP2 header for the channel
      // version.
      stableId_ = 0;
    } else {
      stableId_ = std::numeric_limits<proxygen::HTTPCodec::StreamID>::max();
    }
  }

  ~HTTP2RoutingSessionManager() = default;

  proxygen::HTTPDownstreamSession* createSession(
      folly::AsyncTransportWrapper::UniquePtr sock,
      folly::SocketAddress* peerAddress,
      std::unique_ptr<proxygen::HTTPCodec> h2codec,
      wangle::TransportInfo const& tinfo) {
    // Obtain the proper routing address
    folly::SocketAddress localAddress;
    try {
      sock->getLocalAddress(&localAddress);
    } catch (...) {
      VLOG(3) << "couldn't get local address for socket";
      localAddress = folly::SocketAddress("0.0.0.0", 0);
    }
    VLOG(4) << "Created new session for peer " << *peerAddress;

    // Create the DownstreamSession.  Note that "this" occurs twice
    // because it acts as both a controller as well as a info
    // callback.
    auto session = new proxygen::HTTPDownstreamSession(
        proxygen::WheelTimerInstance(std::chrono::milliseconds(5)),
        std::move(sock),
        localAddress,
        *peerAddress,
        this,
        std::move(h2codec),
        tinfo,
        this);

    return session;
  }

  // begin HTTPSession::InfoCallback methods

  // We do not override onDestroy() to self destroy because this object
  // doubles as both the InfoCallback and the SimpleController.  The
  // session destructor calls onDestroy() first and then detachSession()
  // so we self destroy at detachSession().

  void onSettings(
      const proxygen::HTTPSessionBase&,
      const proxygen::SettingsList& settings) override {
    if (FLAGS_force_channel_version > 0) {
      // Do not use the negotiated settings.
      return;
    }
    for (auto& setting : settings) {
      if (setting.id == kChannelSettingId) {
        negotiatedChannelVersion_ =
            std::min(setting.value, kMaxSupportedChannelVersion);
        VLOG(2) << "Peer channel version is " << setting.value;
        VLOG(2) << "Negotiated channel version is "
                << negotiatedChannelVersion_;
      }
    }
    if (negotiatedChannelVersion_ == 0) {
      // Did not receive a channel version, assuming legacy peer.
      negotiatedChannelVersion_ = 1;
    }
  }

  // end HTTPSession::InfoCallback methods

  // begin SimpleController methods

  proxygen::HTTPTransactionHandler* getRequestHandler(
      proxygen::HTTPTransaction& txn,
      proxygen::HTTPMessage* msg) override {
    folly::SocketAddress clientAddr, vipAddr;
    txn.getPeerAddress(clientAddr);
    txn.getLocalAddress(vipAddr);
    msg->setClientAddress(clientAddr);
    msg->setDstAddress(vipAddr);

    // This checks that the SETTINGS frame arrives before the first RPC.
    DCHECK(negotiatedChannelVersion_ > 0);

    // Determine channel version for this HTTP2 stream.
    uint32_t version = negotiatedChannelVersion_;
    if (UNLIKELY(txn.getID() < stableId_)) {
      auto val = msg->getHeaders().rawGet(kChannelVersionKey);
      try {
        version = folly::to<int>(val);
      } catch (const std::exception& ex) {
        LOG(WARNING) << "Channel version not set properly in header: " << val;
        // This could be from a legacy client.
        version = 1;
      }
      DCHECK(version == 1 || version == negotiatedChannelVersion_);
      if (version == negotiatedChannelVersion_) {
        stableId_ = txn.getID();
      }
    }

    proxygen::RequestHandler* handler =
        new ThriftRequestHandler(processor_, version);
    return new proxygen::RequestHandlerAdaptor(handler);
  }

  void detachSession(const proxygen::HTTPSessionBase*) override {
    VLOG(4) << "HTTP2RoutingSessionManager::detachSession";
    // Session destroyed, so self destroy.
    delete this;
  }

  // end SimpleController methods

 private:
  // Supporting objects for HTTP2 session managed by the callback.
  std::unique_ptr<proxygen::HTTPServerAcceptor> acceptor_;

  ThriftProcessor* processor_;

  // The negotiated channel version - 0 means negotiation has not
  // taken place yet.  Negotiation is completed when the server
  // receives a header with a non-zero channel version.
  uint32_t negotiatedChannelVersion_;

  // The stream id after which the server can assume that the channel
  // version will be the negotiated version.
  proxygen::HTTPCodec::StreamID stableId_;
};

} // anonymous namespace

bool HTTP2RoutingHandler::canAcceptConnection(
    const std::vector<uint8_t>& bytes) {
  /*
   * HTTP/2.0 requests start with the following sequence:
   *   Octal: 0x505249202a20485454502f322e300d0a0d0a534d0d0a0d0a
   *  String: "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
   *
   * For more, see: https://tools.ietf.org/html/rfc7540#section-3.5
   */
  if (bytes[0] == 0x50 && bytes[1] == 0x52 && bytes[2] == 0x49) {
    return true;
  }

  /*
   * HTTP requests start with the following sequence:
   *   Octal: "0x485454502f..."
   *  String: "HTTP/X.X"
   *
   * For more, see: https://tools.ietf.org/html/rfc2616#section-3
   */
  if (bytes[0] == 0x48 && bytes[1] == 0x54 && bytes[2] == 0x54) {
    return true;
  }

  return false;
}

bool HTTP2RoutingHandler::canAcceptEncryptedConnection(
    const std::string& protocolName) {
  return protocolName == "h2" || protocolName == "http";
}

void HTTP2RoutingHandler::handleConnection(
    wangle::ConnectionManager* connectionManager,
    folly::AsyncTransportWrapper::UniquePtr sock,
    folly::SocketAddress* peerAddress,
    wangle::TransportInfo const& tinfo) {
  // Create the DownstreamSession manager.
  auto ipConfig = proxygen::HTTPServer::IPConfig(
      *peerAddress, proxygen::HTTPServer::Protocol::HTTP2);
  auto acceptorConfig =
      proxygen::HTTPServerAcceptor::makeConfig(ipConfig, *options_);
  auto acceptor = proxygen::HTTPServerAcceptor::make(acceptorConfig, *options_);
  auto sessionManager =
      new HTTP2RoutingSessionManager(std::move(acceptor), processor_);
  // Get the HTTP2 Codec
  auto codecFactory = proxygen::HTTPDefaultSessionCodecFactory(acceptorConfig);
  auto h2codec =
      codecFactory.getCodec("h2", proxygen::TransportDirection::DOWNSTREAM);
  // Create the DownstreamSession
  auto session = sessionManager->createSession(
      std::move(sock), peerAddress, std::move(h2codec), tinfo);
  // Set HTTP2 priorities flag on session object.
  session->setHTTP2PrioritiesEnabled(acceptorConfig.HTTP2PrioritiesEnabled);
  /*
  if (acceptorConfig.maxConcurrentIncomingStreams) {
    session->setMaxConcurrentIncomingStreams(
        acceptorConfig.maxConcurrentIncomingStreams);
  }
  */
  // TODO: Improve the way max incoming streams is set
  session->setMaxConcurrentIncomingStreams(100000);

  // Set flow control parameters.
  session->setFlowControl(
      acceptorConfig.initialReceiveWindow,
      acceptorConfig.receiveStreamWindowSize,
      acceptorConfig.receiveSessionWindowSize);
  if (acceptorConfig.writeBufferLimit > 0) {
    session->setWriteBufferLimit(acceptorConfig.writeBufferLimit);
  }
  session->setEgressSettings(
      {{kChannelSettingId, kMaxSupportedChannelVersion}});

  // Route the connection.
  connectionManager->addConnection(session);
  session->startNow();
}

} // namspace thrift
} // namespace apache
<|endoftext|>


<commit_before>#include <stdio.h>
#include <assert.h>
#include <string>

#include <GroundBase.hpp>

#include "Display.h"
#include "GXRenderer.hpp"
#include "GXContext.hpp"
#include "GXLayer.hpp"
#include "GXColor.hpp"

class C1 : public GXLayer
{
public:
    C1(const std::string &fileImg) :
    file(fileImg),
    imgH(-1)
    {}

    void paint( GXContext* context , const GXRect& bounds) override
    {
        context->beginPath();
        //nvgBeginPath(context->_ctx);
        //static int imgH = -1;

        if( imgH == -1)
        {
            imgH = context->createImage(file , 0);// nvgCreateImage(context->_ctx, file.c_str() , 0);
        }

        GXPaint imgPaint = context->imagePattern(GXPointMakeNull(), bounds.size, 0.0f/180.0f*M_PI, imgH, 1.f);
        //nvgImagePattern(context->_ctx, 0, 0, bounds.size.width , bounds.size.height, 0.0f/180.0f*NVG_PI, imgH, 1.f);

        context->addRoundedRect(GXRectMake(GXPointMakeNull(), bounds.size), 5);
        //nvgRoundedRect(context->_ctx, 0,0, bounds.size.width , bounds.size.height, 5);

        context->setFillPainter( imgPaint);
        //nvgFillPaint(context->_ctx, imgPaint);

        context->fill();
        //nvgFill(context->_ctx);
    }

    const std::string file;
    int imgH;
};

class CWin : public GXLayer
{
public:
    CWin()
    {
        str = "Test";
        background =  GXColors::DarkGray;
    }

    void paint( GXContext* context , const GXRect& bounds) override
    {

        context->beginPath();
        //nvgBeginPath( context->_ctx );

        context->addRoundedRect(bounds, 5);
        //nvgRoundedRect(context->_ctx, bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height , 5);
        //nvgFillColor(context->_ctx, background);
        context->setFillColor(background);
        context->fill();
        //nvgFill( context->_ctx );

        const std::string fontName = "Roboto-Regular.ttf";

        int fontHandle = context->createFont(fontName);
        //nvgCreateFont( context->_ctx, fontName.c_str(), fontName.c_str());
        assert( fontHandle != -1);

        context->setFontId( fontHandle);
        //nvgFontFaceId( context->_ctx, fontHandle);

        //nvgFontSize(context->_ctx, 20.f);
        context->setFontSize(20.f);

        context->setFillColor( GXColors::Red );
        //nvgFillColor(context->_ctx, GXColors::Red);

        //const std::string &str = "Hello World";
        //nvgTextBox(context->_ctx, bounds.origin.x, bounds.origin.y, bounds.size.width-20, str.c_str(), NULL);

        context->addTextBox(GXPointMake(20, 20), bounds.size.width-20, str);
        //nvgTextBox(context->_ctx, 20 , 20, bounds.size.width-20, str.c_str(), NULL);

        //nvgText(context->_ctx , bounds.origin.x, bounds.origin.y , str.c_str() , NULL);

    }
    std::string str;
};

static CWin* mainWidget = nullptr;
static CWin* imgWidget = nullptr;
static GXContext* context = nullptr;
static GXRenderer* renderer = nullptr;

static void renderScreen( GXRenderer *render , Display* disp , GXContext *ctx)
{

    //glClearColor(0.0, 0.0f, 0.0f, 1.0f);
    //glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);

    render->draw( ctx );
    DisplaySwap( disp );
    //DisplayWaitEvents( disp );
    DisplayPollEvents( disp );

}

static void eventListener(void* d , const GXEvent *evt)
{
    assert(d);
    assert(evt);

    Display* disp =(Display* ) d;
    assert(disp);

    switch (evt->type)
    {
        case GXEventTypeKey:
        {
            const GXEventKey* key = (const GXEventKey*) evt;
            assert(key);

            if( key->action == GXKeyAction_Press)
            {
                static std::string buf;

                const char* b = GXKeyGetChar(key);
                if( b)
                {
                    if( key->code == GXKey_ENTER)
                    {

                        buf.clear();
                    }
                    else
                    {
                        buf.push_back(b[0]);

                    }
                }
                else if( key->code == GXKey_BACKSPACE)
                {

                    buf.pop_back();// erase(buf.end());
                }
                else
                {
                    printf("Unkown char %i \n" , key->code);
                }
                printf("'%s'\n" , buf.c_str() );
                assert(mainWidget);

                mainWidget->str = buf;
                mainWidget->setNeedsDisplay();
                renderer->renderLayer( context, mainWidget, 1.f);

                /*
                assert(renderer);
                assert(context);

                widget->str = buf;
                renderer->renderLayer( context, widget, 1.f);
                 */

            }
        }
            break;

        case GXEventTypeMouse:
        {
            const GXEventMouse* mouse = (const GXEventMouse*) evt;

            printf("Mouse button %i state %i at (%f,%f) \n" , mouse->button , mouse->state , mouse->x , mouse->y);

            assert(imgWidget);
            imgWidget->bounds.origin = GXPointMake( mouse->x , mouse->y);
            break;
        }

        default:
            assert(false);
            break;
    }
}

int main()
{
    GXRenderer render;

    Display disp;
    {

        /**/
        if( DisplayInit(&disp) == 0)
        {
            printf("Display init error \n");
            return -1;
        }

        int winWidth, winHeight;
        int fbWidth, fbHeight;
        float pxRatio;

        if (!disp._handle)
        {
            return -1;
        }

        DisplayMakeContextCurrent( &disp );

        DisplayGetWindowSize( &disp, &winWidth, &winHeight);
        DisplayGetFramebufferSize( &disp , &fbWidth, &fbHeight);

        DisplaySetEventCallback(&disp, eventListener);

        // Calculate pixel ration for hi-dpi devices.
        pxRatio = (float)fbWidth / (float)winWidth;

        GXContext ctx;

#ifdef USE_GLFW
        assert(DisplayGetType(&disp) == DisplayGLFW);
#elif defined USE_DISPMAN
        assert(DisplayGetType(&disp) == DisplayDispman);
#endif

        /**/

        CWin mainLayer;
        CWin t1;//("images/image1.jpg");
        C1 t2("images/image2.jpg");

        mainWidget = &mainLayer;
        imgWidget = &t1;
        renderer = &render;
        context = &ctx;

        mainLayer.bounds = GXRectMake(0, 0, winWidth, winHeight);
        mainLayer.background = GXColors::LightGray;

        render.setRoot(&mainLayer);
        mainLayer.addChild(&t1);
        //mainLayer.addChild(&t2);

        t1.background = GXColorMake(0.5, 0.5, 0 , 0.5);
        t1.bounds.size = GXSizeMake(200, 200);
        t1.bounds.origin = GXPointMake(40, 10);

        t2.bounds.size = GXSizeMake(200, 200);
        t2.bounds.origin = GXPointMake(140, 160);
        t1.addChild(&t2);
        /*
        mainLayer.setNeedsDisplay();
        t1.setNeedsDisplay();
        t2.setNeedsDisplay();
         */

        GLint defaultFBO = -1;
        glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO);
        assert(defaultFBO == 0);

        render.renderLayer(&ctx, &mainLayer, pxRatio);
        render.renderLayer(&ctx, &t1, pxRatio);
        render.renderLayer(&ctx, &t2, pxRatio);

        //GLint defaultFBO = -1;
        glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO);
        assert(defaultFBO == 0);

        DisplayGetWindowSize( &disp, &winWidth, &winHeight);
        DisplayGetFramebufferSize(&disp, &fbWidth, &fbHeight);
        pxRatio = (float)fbWidth / (float)winWidth;

        glViewport(0, 0, fbWidth, fbHeight);

        GB::RunLoop runL;

        /**/

        GB::Timer t;
        t.setInterval(40);
        t.setCallback([&](GB::Timer &timer)
        {
            GLint defaultFBO = -1;
            glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO);
            assert(defaultFBO == 0);

            renderScreen(&render , &disp , &ctx);

            if( DisplayShouldClose( &disp ))
            {
                runL.stop();
            }
        });

        runL.addSource(t);

        /**/
        /*
        GB::Timer animTime;
        animTime.setInterval(50);
        animTime.setCallback([&t2](GB::Timer &timer)
        {
            t2.bounds.origin += GXPointMake(10, 10);
            if( t2.bounds.origin.y > 600)
            {
                t2.bounds.origin = GXPointMake(10, 10);
            }
        });

        runL.addSource(animTime);
        */
        /**/
        /*
        GB::FDSource input(fileno(stdin));
        input.notification = [&](GBRunLoopSourceNotification notif)
        {
            if( notif == GBRunLoopSourceCanRead)
            {
                static char buf[128];
                if(input.read(buf, 128))
                {
                    printf("Read '%s' \n" , buf);
                }
            }
        };

        runL.addSource(input);
         */
        /**/

        runL.run();
    }

    DisplayRelease(&disp);

	return 0;
}
<commit_msg>Test update<commit_after>#include <stdio.h>
#include <assert.h>
#include <string>

#include <GroundBase.hpp>

#include "Display.h"
#include "GXRenderer.hpp"
#include "GXContext.hpp"
#include "GXLayer.hpp"
#include "GXColor.hpp"

class C1 : public GXLayer
{
public:
    C1(const std::string &fileImg) :
    file(fileImg),
    imgH(-1)
    {}

    void paint( GXContext* context , const GXRect& bounds) override
    {
        context->beginPath();
        //nvgBeginPath(context->_ctx);
        //static int imgH = -1;

        if( imgH == -1)
        {
            imgH = context->createImage(file , 0);// nvgCreateImage(context->_ctx, file.c_str() , 0);
        }

        GXPaint imgPaint = context->imagePattern(GXPointMakeNull(), bounds.size, 0.0f/180.0f*M_PI, imgH, 1.f);
        //nvgImagePattern(context->_ctx, 0, 0, bounds.size.width , bounds.size.height, 0.0f/180.0f*NVG_PI, imgH, 1.f);

        context->addRoundedRect(GXRectMake(GXPointMakeNull(), bounds.size), 5);
        //nvgRoundedRect(context->_ctx, 0,0, bounds.size.width , bounds.size.height, 5);

        context->setFillPainter( imgPaint);
        //nvgFillPaint(context->_ctx, imgPaint);

        context->fill();
        //nvgFill(context->_ctx);
    }

    const std::string file;
    int imgH;
};

class CWin : public GXLayer
{
public:
    CWin()
    {
        str = "Test";
        background =  GXColors::DarkGray;
    }

    void paint( GXContext* context , const GXRect& bounds) override
    {

        context->beginPath();
        //nvgBeginPath( context->_ctx );

        context->addRoundedRect(bounds, 5);
        //nvgRoundedRect(context->_ctx, bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height , 5);
        //nvgFillColor(context->_ctx, background);
        context->setFillColor(background);
        context->fill();
        //nvgFill( context->_ctx );

        const std::string fontName = "Roboto-Regular.ttf";

        int fontHandle = context->createFont(fontName);
        //nvgCreateFont( context->_ctx, fontName.c_str(), fontName.c_str());
        assert( fontHandle != -1);

        context->setFontId( fontHandle);
        //nvgFontFaceId( context->_ctx, fontHandle);

        //nvgFontSize(context->_ctx, 20.f);
        context->setFontSize(20.f);

        context->setFillColor( GXColors::Red );
        //nvgFillColor(context->_ctx, GXColors::Red);

        //const std::string &str = "Hello World";
        //nvgTextBox(context->_ctx, bounds.origin.x, bounds.origin.y, bounds.size.width-20, str.c_str(), NULL);

        context->addTextBox(GXPointMake(20, 20), bounds.size.width-20, str);
        //nvgTextBox(context->_ctx, 20 , 20, bounds.size.width-20, str.c_str(), NULL);

        //nvgText(context->_ctx , bounds.origin.x, bounds.origin.y , str.c_str() , NULL);

    }
    std::string str;
};

static CWin* mainWidget = nullptr;
static CWin* imgWidget = nullptr;
static GXContext* context = nullptr;
static GXRenderer* renderer = nullptr;

static void renderScreen( GXRenderer *render , Display* disp , GXContext *ctx)
{

    //glClearColor(0.0, 0.0f, 0.0f, 1.0f);
    //glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);

    render->draw( ctx );
    DisplaySwap( disp );
    //DisplayWaitEvents( disp );
    DisplayPollEvents( disp );

}

static void eventListener(void* d , const GXEvent *evt)
{
    assert(d);
    assert(evt);

    Display* disp =(Display* ) d;
    assert(disp);

    switch (evt->type)
    {
        case GXEventTypeKey:
        {
            const GXEventKey* key = (const GXEventKey*) evt;
            assert(key);

            if( key->action == GXKeyAction_Press)
            {
                static std::string buf;

                const char* b = GXKeyGetChar(key);
                if( b)
                {
                    if( key->code == GXKey_ENTER)
                    {

                        buf.clear();
                    }
                    else
                    {
                        buf.push_back(b[0]);

                    }
                }
                else if( key->code == GXKey_BACKSPACE)
                {

                    buf.pop_back();// erase(buf.end());
                }
                else
                {
                    printf("Unkown char %i \n" , key->code);
                }
                printf("'%s'\n" , buf.c_str() );
                assert(mainWidget);

                mainWidget->str = buf;
                mainWidget->setNeedsDisplay();
                renderer->renderLayer( context, mainWidget, 1.f);

                /*
                assert(renderer);
                assert(context);

                widget->str = buf;
                renderer->renderLayer( context, widget, 1.f);
                 */

            }
        }
            break;

        case GXEventTypeMouse:
        {
            const GXEventMouse* mouse = (const GXEventMouse*) evt;

            printf("Mouse button %i state %i at (%f,%f) \n" , mouse->button , mouse->state , mouse->x , mouse->y);

            assert(imgWidget);
            imgWidget->bounds.origin = GXPointMake( mouse->x , mouse->y);
            break;
        }

        default:
            assert(false);
            break;
    }
}

int main()
{
    GXRenderer render;

    Display disp;
    {

        /**/
        if( DisplayInit(&disp) == 0)
        {
            printf("Display init error \n");
            return -1;
        }

        int winWidth, winHeight;
        int fbWidth, fbHeight;
        float pxRatio;

        if (!disp._handle)
        {
            return -1;
        }

        DisplayMakeContextCurrent( &disp );

        DisplayGetWindowSize( &disp, &winWidth, &winHeight);
        DisplayGetFramebufferSize( &disp , &fbWidth, &fbHeight);

        DisplaySetEventCallback(&disp, eventListener);

        // Calculate pixel ration for hi-dpi devices.
        pxRatio = (float)fbWidth / (float)winWidth;

        GXContext ctx;

#ifdef USE_GLFW
        assert(DisplayGetType(&disp) == DisplayGLFW);
#elif defined USE_DISPMAN
        assert(DisplayGetType(&disp) == DisplayDispman);
#endif

        /**/

        CWin mainLayer;
        CWin t1;//("images/image1.jpg");
        C1 t2("images/image2.jpg");

        mainWidget = &mainLayer;
        imgWidget = &t1;
        renderer = &render;
        context = &ctx;

        mainLayer.bounds = GXRectMake(0, 0, winWidth, winHeight);
        mainLayer.background = GXColors::LightGray;

        render.setRoot(&mainLayer);
        mainLayer.addChild(&t1);
        //mainLayer.addChild(&t2);

        t1.background = GXColorMake(0.5, 0.5, 0 , 0.5);
        t1.bounds.size = GXSizeMake(200, 200);
        t1.bounds.origin = GXPointMake(40, 10);

        t2.bounds.size = GXSizeMake(200, 200);
        t2.bounds.origin = GXPointMake(140, 160);
        t1.addChild(&t2);
        /*
        mainLayer.setNeedsDisplay();
        t1.setNeedsDisplay();
        t2.setNeedsDisplay();
         */

        /*
        GLint defaultFBO = -1;
        glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO);
        assert(defaultFBO == 0);
        */
        render.renderLayer(&ctx, &mainLayer, pxRatio);
        render.renderLayer(&ctx, &t1, pxRatio);
        render.renderLayer(&ctx, &t2, pxRatio);

        /*
        //GLint defaultFBO = -1;
        glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO);
        assert(defaultFBO == 0);
        */
        DisplayGetWindowSize( &disp, &winWidth, &winHeight);
        DisplayGetFramebufferSize(&disp, &fbWidth, &fbHeight);
        pxRatio = (float)fbWidth / (float)winWidth;

        glViewport(0, 0, fbWidth, fbHeight);

        GB::RunLoop runL;

        /**/

        GB::Timer t;
        t.setInterval(40);
        t.setCallback([&](GB::Timer &timer)
        {
            /*
            GLint defaultFBO = -1;
            glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO);
            assert(defaultFBO == 0);
            */
            renderScreen(&render , &disp , &ctx);

            if( DisplayShouldClose( &disp ))
            {
                runL.stop();
            }
        });

        runL.addSource(t);

        /**/
        /*
        GB::Timer animTime;
        animTime.setInterval(50);
        animTime.setCallback([&t2](GB::Timer &timer)
        {
            t2.bounds.origin += GXPointMake(10, 10);
            if( t2.bounds.origin.y > 600)
            {
                t2.bounds.origin = GXPointMake(10, 10);
            }
        });

        runL.addSource(animTime);
        */
        /**/
        /*
        GB::FDSource input(fileno(stdin));
        input.notification = [&](GBRunLoopSourceNotification notif)
        {
            if( notif == GBRunLoopSourceCanRead)
            {
                static char buf[128];
                if(input.read(buf, 128))
                {
                    printf("Read '%s' \n" , buf);
                }
            }
        };

        runL.addSource(input);
         */
        /**/

        runL.run();
    }

    DisplayRelease(&disp);

	return 0;
}
<|endoftext|>


<commit_before>
/*
 * Copyright (c) 2012 Karl N. Redgate
 *
 * 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 UUID_Module.cc
 * \brief
 *
 */

#include <stdlib.h>

#include <tcl.h>
#include "tcl_util.h"

#include "logger.h"
#include "xuid.h"
#include "UUID.h"
#include "AppInit.h"

namespace { int debug = 0; }

/**
 */
static int
UUID_obj( ClientData data, Tcl_Interp *interp,
             int objc, Tcl_Obj * CONST *objv )
{
    UUID *uuid = (UUID *)data;

    if ( objc == 1 ) {
        Tcl_SetObjResult( interp, Tcl_NewLongObj((long)(uuid)) );
        return TCL_OK;
    }

    char *command = Tcl_GetStringFromObj( objv[1], NULL );
    if ( Tcl_StringMatch(command, "type") ) {
        Svc_SetResult( interp, "UUID", TCL_STATIC );
        return TCL_OK;
    }

    if ( Tcl_StringMatch(command, "data") ) {
        Tcl_Obj *obj = Tcl_NewByteArrayObj( uuid->raw(), 16 );
        Tcl_SetObjResult( interp, obj );
        return TCL_OK;
    }

    if ( Tcl_StringMatch(command, "string") ) {
        Tcl_Obj *obj = Tcl_NewStringObj( uuid->to_s(), -1 );
        Tcl_SetObjResult( interp, obj );
        return TCL_OK;
    }

    if ( Tcl_StringMatch(command, "set") ) {
        if ( objc < 3 ) {
            Tcl_ResetResult( interp );
            Tcl_WrongNumArgs( interp, 1, objv, "set value" );
            return TCL_ERROR;
        }
        char *uuid_string = Tcl_GetStringFromObj( objv[2], NULL );
        uuid->set( uuid_string );
        Tcl_Obj *obj = Tcl_NewStringObj( uuid->to_s(), -1 );
        Tcl_SetObjResult( interp, obj );
        return TCL_OK;
    }

    uint8_t *x = uuid->raw();
    if ( Tcl_StringMatch(command, "dump") ) {
        printf( "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
                x[0], x[1],  x[2],  x[3],  x[4],  x[5],  x[6],  x[7],
                x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15] );
        Tcl_ResetResult( interp );
        return TCL_OK;
    }

    Svc_SetResult( interp, "Unknown command for UUID object", TCL_STATIC );
    return TCL_ERROR;
}

/**
 */
static void
UUID_delete( ClientData data ) {
    UUID *uuid = (UUID *)data;
    delete uuid;
}

/**
 */
static int
UUID_cmd( ClientData data, Tcl_Interp *interp,
             int objc, Tcl_Obj * CONST *objv )
{
    if ( objc < 2 ) {
        Tcl_ResetResult( interp );
        Tcl_WrongNumArgs( interp, 1, objv, "name [value]" );
        return TCL_ERROR;
    }
    char *name = Tcl_GetStringFromObj( objv[1], NULL );

    if ( objc == 2 ) {
        UUID *object = new UUID();
        Tcl_CreateObjCommand( interp, name, UUID_obj, (ClientData)object, UUID_delete );
        Svc_SetResult( interp, name, TCL_VOLATILE );
        return TCL_OK;
    }

    if ( objc != 3 ) {
        Tcl_ResetResult( interp );
        Tcl_WrongNumArgs( interp, 1, objv, "name value" );
        return TCL_ERROR;
    }
    char *uuid_string = Tcl_GetStringFromObj( objv[2], NULL );
    UUID *object = new UUID( uuid_string );
    Tcl_CreateObjCommand( interp, name, UUID_obj, (ClientData)object, UUID_delete );
    Svc_SetResult( interp, name, TCL_VOLATILE );
    return TCL_OK;
}

/**
 */
static int
guid_obj( ClientData data, Tcl_Interp *interp,
             int objc, Tcl_Obj * CONST *objv )
{
    guid_t *guid = (guid_t *)data;
    char buffer[36];

    if ( objc == 1 ) {
        Tcl_SetObjResult( interp, Tcl_NewLongObj((long)(guid)) );
        return TCL_OK;
    }

    char *command = Tcl_GetStringFromObj( objv[1], NULL );
    if ( Tcl_StringMatch(command, "type") ) {
        Svc_SetResult( interp, "UUID", TCL_STATIC );
        return TCL_OK;
    }

#if 0
    if ( Tcl_StringMatch(command, "data") ) {
        Tcl_Obj *obj = Tcl_NewByteArrayObj( uuid->raw(), 16 );
        Tcl_SetObjResult( interp, obj );
        return TCL_OK;
    }
#endif

    if ( Tcl_StringMatch(command, "string") ) {
        format_guid( buffer, guid );
        Tcl_Obj *obj = Tcl_NewStringObj( buffer, 36 );
        Tcl_SetObjResult( interp, obj );
        return TCL_OK;
    }

    if ( Tcl_StringMatch(command, "set") ) {
        if ( objc < 3 ) {
            Tcl_ResetResult( interp );
            Tcl_WrongNumArgs( interp, 1, objv, "set value" );
            return TCL_ERROR;
        }
        char *guid_string = Tcl_GetStringFromObj( objv[2], NULL );
        parse_guid( guid_string, guid );
        format_guid( buffer, guid );
        Tcl_Obj *obj = Tcl_NewStringObj( buffer, 36 );
        Tcl_SetObjResult( interp, obj );
        return TCL_OK;
    }

#if 0
    uint8_t *x = uuid->raw();
    if ( Tcl_StringMatch(command, "dump") ) {
        printf( "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
                x[0], x[1],  x[2],  x[3],  x[4],  x[5],  x[6],  x[7],
                x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15] );
        Tcl_ResetResult( interp );
        return TCL_OK;
    }
#endif

    Svc_SetResult( interp, "Unknown command for UUID object", TCL_STATIC );
    return TCL_ERROR;
}

/**
 */
static void
guid_delete( ClientData data ) {
    guid_t *guid = (guid_t *)data;
    free( guid );
}

/**
 */
static int
guid_cmd( ClientData data, Tcl_Interp *interp,
             int objc, Tcl_Obj * CONST *objv )
{
    if ( objc < 2 ) {
        Tcl_ResetResult( interp );
        Tcl_WrongNumArgs( interp, 1, objv, "name [value]" );
        return TCL_ERROR;
    }
    char *name = Tcl_GetStringFromObj( objv[1], NULL );

    if ( objc == 2 ) {
        guid_t *object = (guid_t *)malloc( sizeof(guid_t) );
        Tcl_CreateObjCommand( interp, name, guid_obj, (ClientData)object, guid_delete );
        Svc_SetResult( interp, name, TCL_VOLATILE );
        return TCL_OK;
    }

    if ( objc != 3 ) {
        Tcl_ResetResult( interp );
        Tcl_WrongNumArgs( interp, 1, objv, "name value" );
        return TCL_ERROR;
    }

    char *guid_string = Tcl_GetStringFromObj( objv[2], NULL );
    guid_t *object = (guid_t *)malloc( sizeof(guid_t) );
    Tcl_CreateObjCommand( interp, name, guid_obj, (ClientData)object, guid_delete );
    Svc_SetResult( interp, name, TCL_VOLATILE );
    return TCL_OK;
}

/**
 */
static bool
UUID_Module( Tcl_Interp *interp ) {
    Tcl_Command command;

    Tcl_Namespace *ns = Tcl_CreateNamespace(interp, "UUID", (ClientData)0, NULL);
    if ( ns == NULL ) {
        return false;
    }

    if ( Tcl_LinkVar(interp, "UUID::debug", (char *)&debug, TCL_LINK_INT) != TCL_OK ) {
        log_err( "failed to link ICMPv6::debug" );
        exit( 1 );
    }

    command = Tcl_CreateObjCommand(interp, "UUID", UUID_cmd, (ClientData)0, NULL);
    if ( command == NULL ) {
        return false;
    }

    return true;
}

app_init( UUID_Module );

/* vim: set autoindent expandtab sw=4 syntax=c : */
<commit_msg>connect guid cmds to interp<commit_after>
/*
 * Copyright (c) 2012 Karl N. Redgate
 *
 * 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 UUID_Module.cc
 * \brief
 *
 */

#include <stdlib.h>

#include <tcl.h>
#include "tcl_util.h"

#include "logger.h"
#include "xuid.h"
#include "UUID.h"
#include "AppInit.h"

namespace { int debug = 0; }

/**
 */
static int
UUID_obj( ClientData data, Tcl_Interp *interp,
             int objc, Tcl_Obj * CONST *objv )
{
    UUID *uuid = (UUID *)data;

    if ( objc == 1 ) {
        Tcl_SetObjResult( interp, Tcl_NewLongObj((long)(uuid)) );
        return TCL_OK;
    }

    char *command = Tcl_GetStringFromObj( objv[1], NULL );
    if ( Tcl_StringMatch(command, "type") ) {
        Svc_SetResult( interp, "UUID", TCL_STATIC );
        return TCL_OK;
    }

    if ( Tcl_StringMatch(command, "data") ) {
        Tcl_Obj *obj = Tcl_NewByteArrayObj( uuid->raw(), 16 );
        Tcl_SetObjResult( interp, obj );
        return TCL_OK;
    }

    if ( Tcl_StringMatch(command, "string") ) {
        Tcl_Obj *obj = Tcl_NewStringObj( uuid->to_s(), -1 );
        Tcl_SetObjResult( interp, obj );
        return TCL_OK;
    }

    if ( Tcl_StringMatch(command, "set") ) {
        if ( objc < 3 ) {
            Tcl_ResetResult( interp );
            Tcl_WrongNumArgs( interp, 1, objv, "set value" );
            return TCL_ERROR;
        }
        char *uuid_string = Tcl_GetStringFromObj( objv[2], NULL );
        uuid->set( uuid_string );
        Tcl_Obj *obj = Tcl_NewStringObj( uuid->to_s(), -1 );
        Tcl_SetObjResult( interp, obj );
        return TCL_OK;
    }

    uint8_t *x = uuid->raw();
    if ( Tcl_StringMatch(command, "dump") ) {
        printf( "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
                x[0], x[1],  x[2],  x[3],  x[4],  x[5],  x[6],  x[7],
                x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15] );
        Tcl_ResetResult( interp );
        return TCL_OK;
    }

    Svc_SetResult( interp, "Unknown command for UUID object", TCL_STATIC );
    return TCL_ERROR;
}

/**
 */
static void
UUID_delete( ClientData data ) {
    UUID *uuid = (UUID *)data;
    delete uuid;
}

/**
 */
static int
UUID_cmd( ClientData data, Tcl_Interp *interp,
             int objc, Tcl_Obj * CONST *objv )
{
    if ( objc < 2 ) {
        Tcl_ResetResult( interp );
        Tcl_WrongNumArgs( interp, 1, objv, "name [value]" );
        return TCL_ERROR;
    }
    char *name = Tcl_GetStringFromObj( objv[1], NULL );

    if ( objc == 2 ) {
        UUID *object = new UUID();
        Tcl_CreateObjCommand( interp, name, UUID_obj, (ClientData)object, UUID_delete );
        Svc_SetResult( interp, name, TCL_VOLATILE );
        return TCL_OK;
    }

    if ( objc != 3 ) {
        Tcl_ResetResult( interp );
        Tcl_WrongNumArgs( interp, 1, objv, "name value" );
        return TCL_ERROR;
    }
    char *uuid_string = Tcl_GetStringFromObj( objv[2], NULL );
    UUID *object = new UUID( uuid_string );
    Tcl_CreateObjCommand( interp, name, UUID_obj, (ClientData)object, UUID_delete );
    Svc_SetResult( interp, name, TCL_VOLATILE );
    return TCL_OK;
}

/**
 */
static int
guid_obj( ClientData data, Tcl_Interp *interp,
             int objc, Tcl_Obj * CONST *objv )
{
    guid_t *guid = (guid_t *)data;
    char buffer[36];

    if ( objc == 1 ) {
        Tcl_SetObjResult( interp, Tcl_NewLongObj((long)(guid)) );
        return TCL_OK;
    }

    char *command = Tcl_GetStringFromObj( objv[1], NULL );
    if ( Tcl_StringMatch(command, "type") ) {
        Svc_SetResult( interp, "UUID", TCL_STATIC );
        return TCL_OK;
    }

#if 0
    if ( Tcl_StringMatch(command, "data") ) {
        Tcl_Obj *obj = Tcl_NewByteArrayObj( uuid->raw(), 16 );
        Tcl_SetObjResult( interp, obj );
        return TCL_OK;
    }
#endif

    if ( Tcl_StringMatch(command, "string") ) {
        format_guid( buffer, guid );
        Tcl_Obj *obj = Tcl_NewStringObj( buffer, 36 );
        Tcl_SetObjResult( interp, obj );
        return TCL_OK;
    }

    if ( Tcl_StringMatch(command, "set") ) {
        if ( objc < 3 ) {
            Tcl_ResetResult( interp );
            Tcl_WrongNumArgs( interp, 1, objv, "set value" );
            return TCL_ERROR;
        }
        char *guid_string = Tcl_GetStringFromObj( objv[2], NULL );
        parse_guid( guid_string, guid );
        format_guid( buffer, guid );
        Tcl_Obj *obj = Tcl_NewStringObj( buffer, 36 );
        Tcl_SetObjResult( interp, obj );
        return TCL_OK;
    }

#if 0
    uint8_t *x = uuid->raw();
    if ( Tcl_StringMatch(command, "dump") ) {
        printf( "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
                x[0], x[1],  x[2],  x[3],  x[4],  x[5],  x[6],  x[7],
                x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15] );
        Tcl_ResetResult( interp );
        return TCL_OK;
    }
#endif

    Svc_SetResult( interp, "Unknown command for UUID object", TCL_STATIC );
    return TCL_ERROR;
}

/**
 */
static void
guid_delete( ClientData data ) {
    guid_t *guid = (guid_t *)data;
    free( guid );
}

/**
 */
static int
guid_cmd( ClientData data, Tcl_Interp *interp,
             int objc, Tcl_Obj * CONST *objv )
{
    if ( objc < 2 ) {
        Tcl_ResetResult( interp );
        Tcl_WrongNumArgs( interp, 1, objv, "name [value]" );
        return TCL_ERROR;
    }
    char *name = Tcl_GetStringFromObj( objv[1], NULL );

    if ( objc == 2 ) {
        guid_t *object = (guid_t *)malloc( sizeof(guid_t) );
        Tcl_CreateObjCommand( interp, name, guid_obj, (ClientData)object, guid_delete );
        Svc_SetResult( interp, name, TCL_VOLATILE );
        return TCL_OK;
    }

    if ( objc != 3 ) {
        Tcl_ResetResult( interp );
        Tcl_WrongNumArgs( interp, 1, objv, "name value" );
        return TCL_ERROR;
    }

    char *guid_string = Tcl_GetStringFromObj( objv[2], NULL );
    guid_t *object = (guid_t *)malloc( sizeof(guid_t) );
    Tcl_CreateObjCommand( interp, name, guid_obj, (ClientData)object, guid_delete );
    Svc_SetResult( interp, name, TCL_VOLATILE );
    return TCL_OK;
}

/**
 */
static bool
UUID_Module( Tcl_Interp *interp ) {
    Tcl_Command command;

    Tcl_Namespace *ns = Tcl_CreateNamespace(interp, "UUID", (ClientData)0, NULL);
    if ( ns == NULL ) {
        return false;
    }

    if ( Tcl_LinkVar(interp, "UUID::debug", (char *)&debug, TCL_LINK_INT) != TCL_OK ) {
        log_err( "failed to link ICMPv6::debug" );
        exit( 1 );
    }

    command = Tcl_CreateObjCommand(interp, "UUID::UUID", UUID_cmd, (ClientData)0, NULL);
    if ( command == NULL ) {
        return false;
    }

    command = Tcl_CreateObjCommand(interp, "UUID::guid", guid_cmd, (ClientData)0, NULL);
    if ( command == NULL ) {
        // logger ?? want to report TCL Error
        return false;
    }

    return true;
}

app_init( UUID_Module );

/* vim: set autoindent expandtab sw=4 syntax=c : */
<|endoftext|>


<commit_before>/**@file Module for managing Linux signals and allowing multiple handlers per signal. */
/*
* Copyright 2014 Range Networks, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.

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

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

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

*/

#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cerrno>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#include "coredumper.h"
#include "UnixSignal.h"
#include "Logger.h"

//UnixSignal gSigVec;

static void _sigHandler(int sig)
{
    signal(sig, SIG_IGN);
    if (sig <= 0 || sig >= UnixSignal::C_NSIG)
    {
	LOG(ERR) << "Signal Handler for signal " << sig << " (out of range)";
	return;
    }
    // work around C++ issue with function pointers and class based function pointers
    gSigVec.Handler(sig);
    signal(sig, SIG_DFL);
    printf("Rethrowing signal %d\n", sig);
    kill(getpid(), sig);
}

void UnixSignal::Handler(int sig)
{
    // Only write core files for the signals that need core
    switch(sig)
    {
    case SIGQUIT: case SIGILL: case SIGABRT: case SIGFPE: case SIGSEGV:
    case SIGBUS: case SIGSYS: case SIGTRAP: case SIGXCPU: case SIGXFSZ:
	{
	    char buf[BUFSIZ];
	    if (mAddPid)
		snprintf(buf, sizeof(buf)-1, "%s.%d", mCoreFile.c_str(), getpid());
	    else
		snprintf(buf, sizeof(buf)-1, "%s", mCoreFile.c_str());
	    WriteCoreDump(buf);

	    // and save the files if needed
	    if (mSaveFiles)
	    {
	    	char buf[BUFSIZ];
		std::string s;
		std::string p;
		sprintf(buf, "%d", getpid());
		p = buf;
		s  = "rm -rf /tmp/staging." ; s += p; s += "/ ; ";
		s += "mkdir /tmp/staging." ; s += p; s += "/ ; ";
		s += "cp --parents /etc/issue /tmp/staging." ; s += p; s += "/ ; ";
		s += "cp --parents /proc/cpuinfo /proc/interrupts /proc/iomem /proc/ioports /proc/diskstats /proc/loadavg /proc/locks /proc/meminfo /proc/softirqs /proc/stat /proc/uptime /proc/version /proc/version_signature /proc/vmstat /tmp/staging." ; s += p; s += "/ ; ";

		s += "for i in cmdline cpuset environ io limits maps net/tcp net/udp net/tcp6 net/udp6 net/unix net/netstat sched schedstat smaps stat statm status ; ";
		s += "do cp --parents /proc/" ; s += p; s += "/$i /tmp/staging." ; s += p; s += "/ ; ";
		s += "cp --parents /proc/"; s += p; s += "/task/*/stat* /tmp/staging."; s += p; s += "/ ; ";
		s += "done ; ";
		s += "tar --create --verbose --file=- --directory=/proc/"; s += p; s += " fd | ( cd /tmp/staging."; s += p; s += "/proc/"; s += p; s += "/ ; tar xpvf - ) ; ";
		s += "tar --create --verbose --file=- --directory=/tmp/staging."; s += p; s += "/ . | gzip > "; s += mTarFile; s += " ; ";
		s += "rm -rf /tmp/staging." ; s += p;
		printf("Running '%s'\n", s.c_str());
		system(s.c_str());
	    }
	}
	break;
    default:
	break;
    }

    printf("Processing signal vector for sig %d\n", sig);
    mLock[sig].lock();
    for (std::list<sighandler_t>::iterator i = mListHandlers[sig].begin();
	i != mListHandlers[sig].end(); i++)
    {
    	(*i)(sig);
    }
    mLock[sig].unlock();
    printf("Done processing signal vector for sig %d\n", sig);
}

UnixSignal::UnixSignal(void)
{
    for (int i = 0; i < C_NSIG; i++)
    {
	mListHandlers[i].clear();
	//signal(i, _sigHandler);
    }
    mAddPid = false;
    mCoreFile = "core";
}

UnixSignal::~UnixSignal(void)
{
    for (int i = 0; i < C_NSIG; i++)
    {
	mListHandlers[i].clear();
	signal(i, SIG_DFL);
    }
}

void UnixSignal::Register(sighandler_t handler, int sig) // register the handler to the signal
{
    if (sig <= 0 || sig >= C_NSIG)
    {
	LOG(ERR) << "Unable to register callback for UnixSignal " << sig << " (out of range)";
	return;
    }
    mLock[sig].lock();
    signal(sig, _sigHandler); // only catch signals that have been registered
    mListHandlers[sig].insert(mListHandlers[sig].end(), handler);
    mLock[sig].unlock();
}

void UnixSignal::Dump(void)
{
    for (int sig = 0; sig < C_NSIG; sig++)
    {
	mLock[sig].lock();
	if (mListHandlers[sig].size() != 0)
	{
	    printf("Signal vectors for signal %d: ", sig);
	    for (std::list<sighandler_t>::iterator i = mListHandlers[sig].begin();
		i != mListHandlers[sig].end(); i++)
	    {
		printf("%s0x%p", i == mListHandlers[sig].begin() ? "" : ", ", *i);
	    }
	    printf("\n");
	}
	mLock[sig].unlock();
    }
}
<commit_msg>- remove need for 3rdParty include reference, libcoredump now can be built-from-scratch and installed as lib and -dev headers<commit_after>/**@file Module for managing Linux signals and allowing multiple handlers per signal. */
/*
* Copyright 2014 Range Networks, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.

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

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

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

*/

#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cerrno>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <google/coredumper.h>

#include "UnixSignal.h"
#include "Logger.h"

//UnixSignal gSigVec;

static void _sigHandler(int sig)
{
    signal(sig, SIG_IGN);
    if (sig <= 0 || sig >= UnixSignal::C_NSIG)
    {
	LOG(ERR) << "Signal Handler for signal " << sig << " (out of range)";
	return;
    }
    // work around C++ issue with function pointers and class based function pointers
    gSigVec.Handler(sig);
    signal(sig, SIG_DFL);
    printf("Rethrowing signal %d\n", sig);
    kill(getpid(), sig);
}

void UnixSignal::Handler(int sig)
{
    // Only write core files for the signals that need core
    switch(sig)
    {
    case SIGQUIT: case SIGILL: case SIGABRT: case SIGFPE: case SIGSEGV:
    case SIGBUS: case SIGSYS: case SIGTRAP: case SIGXCPU: case SIGXFSZ:
	{
	    char buf[BUFSIZ];
	    if (mAddPid)
		snprintf(buf, sizeof(buf)-1, "%s.%d", mCoreFile.c_str(), getpid());
	    else
		snprintf(buf, sizeof(buf)-1, "%s", mCoreFile.c_str());
	    WriteCoreDump(buf);

	    // and save the files if needed
	    if (mSaveFiles)
	    {
	    	char buf[BUFSIZ];
		std::string s;
		std::string p;
		sprintf(buf, "%d", getpid());
		p = buf;
		s  = "rm -rf /tmp/staging." ; s += p; s += "/ ; ";
		s += "mkdir /tmp/staging." ; s += p; s += "/ ; ";
		s += "cp --parents /etc/issue /tmp/staging." ; s += p; s += "/ ; ";
		s += "cp --parents /proc/cpuinfo /proc/interrupts /proc/iomem /proc/ioports /proc/diskstats /proc/loadavg /proc/locks /proc/meminfo /proc/softirqs /proc/stat /proc/uptime /proc/version /proc/version_signature /proc/vmstat /tmp/staging." ; s += p; s += "/ ; ";

		s += "for i in cmdline cpuset environ io limits maps net/tcp net/udp net/tcp6 net/udp6 net/unix net/netstat sched schedstat smaps stat statm status ; ";
		s += "do cp --parents /proc/" ; s += p; s += "/$i /tmp/staging." ; s += p; s += "/ ; ";
		s += "cp --parents /proc/"; s += p; s += "/task/*/stat* /tmp/staging."; s += p; s += "/ ; ";
		s += "done ; ";
		s += "tar --create --verbose --file=- --directory=/proc/"; s += p; s += " fd | ( cd /tmp/staging."; s += p; s += "/proc/"; s += p; s += "/ ; tar xpvf - ) ; ";
		s += "tar --create --verbose --file=- --directory=/tmp/staging."; s += p; s += "/ . | gzip > "; s += mTarFile; s += " ; ";
		s += "rm -rf /tmp/staging." ; s += p;
		printf("Running '%s'\n", s.c_str());
		system(s.c_str());
	    }
	}
	break;
    default:
	break;
    }

    printf("Processing signal vector for sig %d\n", sig);
    mLock[sig].lock();
    for (std::list<sighandler_t>::iterator i = mListHandlers[sig].begin();
	i != mListHandlers[sig].end(); i++)
    {
    	(*i)(sig);
    }
    mLock[sig].unlock();
    printf("Done processing signal vector for sig %d\n", sig);
}

UnixSignal::UnixSignal(void)
{
    for (int i = 0; i < C_NSIG; i++)
    {
	mListHandlers[i].clear();
	//signal(i, _sigHandler);
    }
    mAddPid = false;
    mCoreFile = "core";
}

UnixSignal::~UnixSignal(void)
{
    for (int i = 0; i < C_NSIG; i++)
    {
	mListHandlers[i].clear();
	signal(i, SIG_DFL);
    }
}

void UnixSignal::Register(sighandler_t handler, int sig) // register the handler to the signal
{
    if (sig <= 0 || sig >= C_NSIG)
    {
	LOG(ERR) << "Unable to register callback for UnixSignal " << sig << " (out of range)";
	return;
    }
    mLock[sig].lock();
    signal(sig, _sigHandler); // only catch signals that have been registered
    mListHandlers[sig].insert(mListHandlers[sig].end(), handler);
    mLock[sig].unlock();
}

void UnixSignal::Dump(void)
{
    for (int sig = 0; sig < C_NSIG; sig++)
    {
	mLock[sig].lock();
	if (mListHandlers[sig].size() != 0)
	{
	    printf("Signal vectors for signal %d: ", sig);
	    for (std::list<sighandler_t>::iterator i = mListHandlers[sig].begin();
		i != mListHandlers[sig].end(); i++)
	    {
		printf("%s0x%p", i == mListHandlers[sig].begin() ? "" : ", ", *i);
	    }
	    printf("\n");
	}
	mLock[sig].unlock();
    }
}
<|endoftext|>


<commit_before>#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>

#include "Plane.h"
#include "Shader.h"
#include "Texture.h"
#include "GameTime.h"

#pragma region Variables

GLFWwindow* window;

GameTime gameTime;

GLuint shader;
GLuint shader2;

GLuint waterTex;
GLuint tex;

Plane* plane;
Plane* plane2;

Camera cam;

glm::vec2 mousePosLast;
#pragma endregion

#pragma region Function Headers

void setupWindowAndContext();

void update();
void render();

#pragma endregion
int main()
{
	setupWindowAndContext();

	glClearColor(100/255.0f, 149/255.0f, 237/255.0f, 1.0f);

	shader = loadShader("vertex.glsl", "fragment.phong.glsl");
	shader2 = loadShader("vertex.glsl", "fragment.glsl");

	plane = new Plane();

	plane2 = new Plane();

	cam.position = glm::vec3(3, 5, 3);
	//cam.direction = glm::vec3(1, 1, 0);

	cam.light = glm::vec3(0.0f, 0.0f, 0.0f);

	waterTex = loadTexture("water3.jpg");
	//waterTex = loadTexture("18_vertex_texture_02.jpg");
	plane->texture=waterTex;
	tex = loadTexture("rubber_duck-1331px.png");
	tex = loadTexture("pebbles2.jpg");

	//tex = loadTexture("magic.jpg");
	glActiveTexture(GL_TEXTURE1);
	glBindTexture(GL_TEXTURE_2D, tex);
	glActiveTexture(GL_TEXTURE0);
	plane2->texture = tex;

	while(!glfwWindowShouldClose(window))
	{
		update();
		render();
	}
	return 0;
}

void setupWindowAndContext()
{
	if(!glfwInit())
	{
		std::cout << "GLFW Failed to Initialize!" << std::endl;
		exit(EXIT_FAILURE);
	}

	glfwWindowHint(GLFW_DECORATED, GL_FALSE);
	glfwWindowHint(GLFW_VISIBLE, GL_FALSE);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	window = glfwCreateWindow(WIN_WIDTH, WIN_HEIGHT, "OpenGL Water Demo", NULL, NULL);
	glfwShowWindow(window);
	glfwMakeContextCurrent(window);

	glewExperimental = true;
	if(glewInit() != GLEW_OK)
	{
		std::cout << "Glew Failed to Initialize!" << std::endl;
		exit(EXIT_FAILURE);
	}
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}

void update()
{
	gameTime.Update();
	//cam.position -= glm::vec3(0.5f,1.0f,0) * gameTime.GetDeltaTimeSecondsF();
	cam.light -= glm::vec3(0.1f,0.2f,0) * gameTime.GetDeltaTimeSecondsF();

	cam.UpdateRotation(window, 20.0f * gameTime.GetDeltaTimeSecondsF());

	//Camera Rotations
	double xpos, ypos;
	glfwGetCursorPos(window, &xpos, &ypos);
	//cam.Rotation(-(xpos-mousePosLast.x), glm::vec3(0, 1, 0));
	//cam.Rotation((ypos-mousePosLast.y), glm::vec3(1, 0, 0));
	mousePosLast = glm::vec2(xpos, ypos);

	//Camera Translations
	glm::vec3 vel;
	if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
	{
		vel += glm::vec3(-1, 0, 0);
	}
	if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
	{
		vel += glm::vec3(1, 0, 0);
	}
	if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
	{
		vel += glm::vec3(0, 0, 1);
	}
	if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
	{
		vel += glm::vec3(0, 0, -1);
	}

	if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS)
	{
		shader = loadShader("vertex.glsl", "fragment.phong.glsl");
	}

	vel *= gameTime.GetDeltaTimeSecondsF();

	cam.Translate(vel);

	glfwPollEvents();
}

void render()
{
	glClear(GL_COLOR_BUFFER_BIT);

	//plane2->Draw(shader2, cam);
	plane->Draw(shader, cam);

	glfwSwapBuffers(window);
}
<commit_msg>Set default camera rotation<commit_after>#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>

#include "Plane.h"
#include "Shader.h"
#include "Texture.h"
#include "GameTime.h"

#pragma region Variables

GLFWwindow* window;

GameTime gameTime;

GLuint shader;
GLuint shader2;

GLuint waterTex;
GLuint tex;

Plane* plane;
Plane* plane2;

Camera cam;

glm::vec2 mousePosLast;
#pragma endregion

#pragma region Function Headers

void setupWindowAndContext();

void update();
void render();

#pragma endregion
int main()
{
	setupWindowAndContext();

	glClearColor(100/255.0f, 149/255.0f, 237/255.0f, 1.0f);

	shader = loadShader("vertex.glsl", "fragment.phong.glsl");
	shader2 = loadShader("vertex.glsl", "fragment.glsl");

	plane = new Plane();

	plane2 = new Plane();

	cam.position = glm::vec3(3, 5, 3);
	//cam.direction = glm::vec3(1, 1, 0);

	cam.light = glm::vec3(0.0f, 0.0f, 0.0f);

	waterTex = loadTexture("water3.jpg");
	//waterTex = loadTexture("18_vertex_texture_02.jpg");
	plane->texture=waterTex;
	tex = loadTexture("rubber_duck-1331px.png");
	tex = loadTexture("pebbles2.jpg");

	//tex = loadTexture("magic.jpg");
	glActiveTexture(GL_TEXTURE1);
	glBindTexture(GL_TEXTURE_2D, tex);
	glActiveTexture(GL_TEXTURE0);
	plane2->texture = tex;

	cam.rotation = glm::vec3(-173, -142, 0);

	while(!glfwWindowShouldClose(window))
	{
		update();
		render();
	}
	return 0;
}

void setupWindowAndContext()
{
	if(!glfwInit())
	{
		std::cout << "GLFW Failed to Initialize!" << std::endl;
		exit(EXIT_FAILURE);
	}

	glfwWindowHint(GLFW_DECORATED, GL_FALSE);
	glfwWindowHint(GLFW_VISIBLE, GL_FALSE);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	window = glfwCreateWindow(WIN_WIDTH, WIN_HEIGHT, "OpenGL Water Demo", NULL, NULL);
	glfwShowWindow(window);
	glfwMakeContextCurrent(window);

	glewExperimental = true;
	if(glewInit() != GLEW_OK)
	{
		std::cout << "Glew Failed to Initialize!" << std::endl;
		exit(EXIT_FAILURE);
	}
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}

void update()
{
	gameTime.Update();
	//cam.position -= glm::vec3(0.5f,1.0f,0) * gameTime.GetDeltaTimeSecondsF();
	cam.light -= glm::vec3(0.1f,0.2f,0) * gameTime.GetDeltaTimeSecondsF();

	cam.UpdateRotation(window, 20.0f * gameTime.GetDeltaTimeSecondsF());

	//Camera Rotations
	double xpos, ypos;
	glfwGetCursorPos(window, &xpos, &ypos);
	//cam.Rotation(-(xpos-mousePosLast.x), glm::vec3(0, 1, 0));
	//cam.Rotation((ypos-mousePosLast.y), glm::vec3(1, 0, 0));
	mousePosLast = glm::vec2(xpos, ypos);

	//Camera Translations
	glm::vec3 vel;
	if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
	{
		vel += glm::vec3(-1, 0, 0);
	}
	if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
	{
		vel += glm::vec3(1, 0, 0);
	}
	if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
	{
		vel += glm::vec3(0, 0, 1);
	}
	if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
	{
		vel += glm::vec3(0, 0, -1);
	}

	if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS)
	{
		shader = loadShader("vertex.glsl", "fragment.phong.glsl");
	}

	vel *= gameTime.GetDeltaTimeSecondsF();

	cam.Translate(vel);

	glfwPollEvents();
}

void render()
{
	glClear(GL_COLOR_BUFFER_BIT);

	//plane2->Draw(shader2, cam);
	plane->Draw(shader, cam);

	glfwSwapBuffers(window);
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// 	Copyright (c) 2015 Sergey Makeev, Vadim Slyusarev
//
// 	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.

#include <MTScheduler.h>

namespace MT
{
	FiberContext::FiberContext()
		: threadContext(nullptr)
		, taskStatus(FiberTaskStatus::UNKNOWN)
		, childrenFibersCount(0)
		, parentFiber(nullptr)
		, stackRequirements(StackRequirements::INVALID)
	{
	}

	void FiberContext::SetStatus(FiberTaskStatus::Type _taskStatus)
	{
		MT_ASSERT(threadContext, "Sanity check failed");
		MT_ASSERT(threadContext->thread.IsCurrentThread(), "You can change task status only from owner thread");
		taskStatus = _taskStatus;
	}

	FiberTaskStatus::Type FiberContext::GetStatus() const
	{
		return taskStatus;
	}

	void FiberContext::SetThreadContext(internal::ThreadContext * _threadContext)
	{
		if (_threadContext)
		{
			_threadContext->lastActiveFiberContext = this;
		}

		threadContext = _threadContext;
	}

	internal::ThreadContext* FiberContext::GetThreadContext()
	{
		return threadContext;
	}

	void FiberContext::Reset()
	{
		MT_ASSERT(childrenFibersCount.Load() == 0, "Can't release fiber with active children fibers");
		currentTask = internal::TaskDesc();
		parentFiber = nullptr;
		threadContext = nullptr;
		stackRequirements = StackRequirements::INVALID;
	}

	void FiberContext::WaitGroupAndYield(TaskGroup group)
	{
		MT_ASSERT(threadContext, "Sanity check failed!");
		MT_ASSERT(threadContext->taskScheduler, "Sanity check failed!");
		MT_ASSERT(threadContext->taskScheduler->IsWorkerThread(), "Can't use WaitGroupAndYield outside Task. Use TaskScheduler.WaitGroup() instead.");
		MT_ASSERT(threadContext->thread.IsCurrentThread(), "Thread context sanity check failed");

		MT_VERIFY(group != currentGroup, "Can't wait the same group. Deadlock detected!", return);
		MT_VERIFY(group.IsValid(), "Invalid group!", return);

		TaskScheduler::TaskGroupDescription  & groupDesc = threadContext->taskScheduler->GetGroupDesc(group);

		ConcurrentQueueLIFO<FiberContext*> & groupQueue = groupDesc.GetWaitQueue();

		// Change status
		taskStatus = FiberTaskStatus::AWAITING_GROUP;

		// Add current fiber to awaiting queue
		groupQueue.Push(this);

		Fiber & schedulerFiber = threadContext->schedulerFiber;

#ifdef MT_INSTRUMENTED_BUILD
		threadContext->NotifyTaskYielded(currentTask);
#endif

		// Yielding, so reset thread context
		threadContext = nullptr;

		//switch to scheduler
		Fiber::SwitchTo(fiber, schedulerFiber);
	}

	void FiberContext::RunSubtasksAndYieldImpl(ArrayView<internal::TaskBucket>& buckets)
	{
		MT_ASSERT(threadContext, "Sanity check failed!");
		MT_ASSERT(threadContext->taskScheduler, "Sanity check failed!");
		MT_ASSERT(threadContext->taskScheduler->IsWorkerThread(), "Can't use RunSubtasksAndYield outside Task. Use TaskScheduler.WaitGroup() instead.");
		MT_ASSERT(threadContext->thread.IsCurrentThread(), "Thread context sanity check failed");

		// add to scheduler
		threadContext->taskScheduler->RunTasksImpl(buckets, this, false);

		//
		MT_ASSERT(threadContext->thread.IsCurrentThread(), "Thread context sanity check failed");

		// Change status
		taskStatus = FiberTaskStatus::AWAITING_CHILD;

		Fiber & schedulerFiber = threadContext->schedulerFiber;

#ifdef MT_INSTRUMENTED_BUILD
		threadContext->NotifyTaskYielded(currentTask);
#endif

		// Yielding, so reset thread context
		threadContext = nullptr;

		//switch to scheduler
		Fiber::SwitchTo(fiber, schedulerFiber);
	}

	void FiberContext::RunAsync(TaskGroup taskGroup, const TaskHandle* taskHandleArray, uint32 taskHandleCount)
	{
		MT_ASSERT(threadContext, "ThreadContext is nullptr");
		MT_ASSERT(threadContext->taskScheduler, "Sanity check failed!");
		MT_ASSERT(threadContext->taskScheduler->IsWorkerThread(), "Can't use RunAsync outside Task. Use TaskScheduler.RunAsync() instead.");

		TaskScheduler& scheduler = *(threadContext->taskScheduler);

		ArrayView<internal::GroupedTask> buffer(threadContext->descBuffer, taskHandleCount);

		uint32 bucketCount = MT::Min((uint32)scheduler.GetWorkersCount(), taskHandleCount);
		ArrayView<internal::TaskBucket>	buckets(MT_ALLOCATE_ON_STACK(sizeof(internal::TaskBucket) * bucketCount), bucketCount);

		internal::DistibuteDescriptions(taskGroup, taskHandleArray, buffer, buckets);
		scheduler.RunTasksImpl(buckets, nullptr, false);
	}

	void FiberContext::RunSubtasksAndYield(TaskGroup taskGroup, const TaskHandle* taskHandleArray, uint32 taskHandleCount)
	{
		MT_ASSERT(threadContext, "ThreadContext is nullptr");
		MT_ASSERT(threadContext->taskScheduler, "TaskScheduler is nullptr");

		MT_ASSERT(taskHandleCount < internal::TASK_BUFFER_CAPACITY, "Buffer overrun!");

		TaskScheduler& scheduler = *(threadContext->taskScheduler);

		ArrayView<internal::GroupedTask> buffer(threadContext->descBuffer, taskHandleCount);

		uint32 bucketCount = MT::Min((uint32)scheduler.GetWorkersCount(), taskHandleCount);
		ArrayView<internal::TaskBucket> buckets(MT_ALLOCATE_ON_STACK(sizeof(internal::TaskBucket) * bucketCount), bucketCount);

		internal::DistibuteDescriptions(taskGroup, taskHandleArray, buffer, buckets);
		RunSubtasksAndYieldImpl(buckets);
	}

}
<commit_msg>fixed field initialization warning<commit_after>// The MIT License (MIT)
//
// 	Copyright (c) 2015 Sergey Makeev, Vadim Slyusarev
//
// 	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.

#include <MTScheduler.h>

namespace MT
{
	FiberContext::FiberContext()
		: threadContext(nullptr)
		, taskStatus(FiberTaskStatus::UNKNOWN)
		, stackRequirements(StackRequirements::INVALID)
		, childrenFibersCount(0)
		, parentFiber(nullptr)
	{
	}

	void FiberContext::SetStatus(FiberTaskStatus::Type _taskStatus)
	{
		MT_ASSERT(threadContext, "Sanity check failed");
		MT_ASSERT(threadContext->thread.IsCurrentThread(), "You can change task status only from owner thread");
		taskStatus = _taskStatus;
	}

	FiberTaskStatus::Type FiberContext::GetStatus() const
	{
		return taskStatus;
	}

	void FiberContext::SetThreadContext(internal::ThreadContext * _threadContext)
	{
		if (_threadContext)
		{
			_threadContext->lastActiveFiberContext = this;
		}

		threadContext = _threadContext;
	}

	internal::ThreadContext* FiberContext::GetThreadContext()
	{
		return threadContext;
	}

	void FiberContext::Reset()
	{
		MT_ASSERT(childrenFibersCount.Load() == 0, "Can't release fiber with active children fibers");
		currentTask = internal::TaskDesc();
		parentFiber = nullptr;
		threadContext = nullptr;
		stackRequirements = StackRequirements::INVALID;
	}

	void FiberContext::WaitGroupAndYield(TaskGroup group)
	{
		MT_ASSERT(threadContext, "Sanity check failed!");
		MT_ASSERT(threadContext->taskScheduler, "Sanity check failed!");
		MT_ASSERT(threadContext->taskScheduler->IsWorkerThread(), "Can't use WaitGroupAndYield outside Task. Use TaskScheduler.WaitGroup() instead.");
		MT_ASSERT(threadContext->thread.IsCurrentThread(), "Thread context sanity check failed");

		MT_VERIFY(group != currentGroup, "Can't wait the same group. Deadlock detected!", return);
		MT_VERIFY(group.IsValid(), "Invalid group!", return);

		TaskScheduler::TaskGroupDescription  & groupDesc = threadContext->taskScheduler->GetGroupDesc(group);

		ConcurrentQueueLIFO<FiberContext*> & groupQueue = groupDesc.GetWaitQueue();

		// Change status
		taskStatus = FiberTaskStatus::AWAITING_GROUP;

		// Add current fiber to awaiting queue
		groupQueue.Push(this);

		Fiber & schedulerFiber = threadContext->schedulerFiber;

#ifdef MT_INSTRUMENTED_BUILD
		threadContext->NotifyTaskYielded(currentTask);
#endif

		// Yielding, so reset thread context
		threadContext = nullptr;

		//switch to scheduler
		Fiber::SwitchTo(fiber, schedulerFiber);
	}

	void FiberContext::RunSubtasksAndYieldImpl(ArrayView<internal::TaskBucket>& buckets)
	{
		MT_ASSERT(threadContext, "Sanity check failed!");
		MT_ASSERT(threadContext->taskScheduler, "Sanity check failed!");
		MT_ASSERT(threadContext->taskScheduler->IsWorkerThread(), "Can't use RunSubtasksAndYield outside Task. Use TaskScheduler.WaitGroup() instead.");
		MT_ASSERT(threadContext->thread.IsCurrentThread(), "Thread context sanity check failed");

		// add to scheduler
		threadContext->taskScheduler->RunTasksImpl(buckets, this, false);

		//
		MT_ASSERT(threadContext->thread.IsCurrentThread(), "Thread context sanity check failed");

		// Change status
		taskStatus = FiberTaskStatus::AWAITING_CHILD;

		Fiber & schedulerFiber = threadContext->schedulerFiber;

#ifdef MT_INSTRUMENTED_BUILD
		threadContext->NotifyTaskYielded(currentTask);
#endif

		// Yielding, so reset thread context
		threadContext = nullptr;

		//switch to scheduler
		Fiber::SwitchTo(fiber, schedulerFiber);
	}

	void FiberContext::RunAsync(TaskGroup taskGroup, const TaskHandle* taskHandleArray, uint32 taskHandleCount)
	{
		MT_ASSERT(threadContext, "ThreadContext is nullptr");
		MT_ASSERT(threadContext->taskScheduler, "Sanity check failed!");
		MT_ASSERT(threadContext->taskScheduler->IsWorkerThread(), "Can't use RunAsync outside Task. Use TaskScheduler.RunAsync() instead.");

		TaskScheduler& scheduler = *(threadContext->taskScheduler);

		ArrayView<internal::GroupedTask> buffer(threadContext->descBuffer, taskHandleCount);

		uint32 bucketCount = MT::Min((uint32)scheduler.GetWorkersCount(), taskHandleCount);
		ArrayView<internal::TaskBucket>	buckets(MT_ALLOCATE_ON_STACK(sizeof(internal::TaskBucket) * bucketCount), bucketCount);

		internal::DistibuteDescriptions(taskGroup, taskHandleArray, buffer, buckets);
		scheduler.RunTasksImpl(buckets, nullptr, false);
	}

	void FiberContext::RunSubtasksAndYield(TaskGroup taskGroup, const TaskHandle* taskHandleArray, uint32 taskHandleCount)
	{
		MT_ASSERT(threadContext, "ThreadContext is nullptr");
		MT_ASSERT(threadContext->taskScheduler, "TaskScheduler is nullptr");

		MT_ASSERT(taskHandleCount < internal::TASK_BUFFER_CAPACITY, "Buffer overrun!");

		TaskScheduler& scheduler = *(threadContext->taskScheduler);

		ArrayView<internal::GroupedTask> buffer(threadContext->descBuffer, taskHandleCount);

		uint32 bucketCount = MT::Min((uint32)scheduler.GetWorkersCount(), taskHandleCount);
		ArrayView<internal::TaskBucket> buckets(MT_ALLOCATE_ON_STACK(sizeof(internal::TaskBucket) * bucketCount), bucketCount);

		internal::DistibuteDescriptions(taskGroup, taskHandleArray, buffer, buckets);
		RunSubtasksAndYieldImpl(buckets);
	}

}
<|endoftext|>


<commit_before>/** \brief Tool to adjust validation rules for journal set to selective
 *         evaluation to avoid failing QS checks for field not eligible
 *         in this context
 *  \author Johannes Riedl
 *
 *  \copyright 2021 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <iostream>
#include "Compiler.h"
#include "DbConnection.h"
#include "DbResultSet.h"
#include "DbRow.h"
#include "StringUtil.h"
#include "UBTools.h"
#include "util.h"
#include "ZoteroHarvesterConfig.h"

namespace {

using namespace ZoteroHarvester;

[[noreturn]] void Usage() {
    std::cerr << "Usage: " << ::progname << " zotero_harvester.conf\n";
    std::exit(EXIT_FAILURE);
}

std::string AssembleValaditionRulesIfNotExist(const std::string journal_id)
{
    const auto tag("084");
    const std::vector<char> subfield_codes({ 'a', '2' });
    const std::vector<std::string> record_types({"regular_article", "review"});
    std::vector<std::string> values;
    const auto field_presence("ignore");
    // The following is the logic for "Insert if not exists beforehand"
    // The SELECTs in the for loop generate anonymous tuples that are merged in an multi row table by UNION ALL
    for (const auto &subfield_code : subfield_codes)
        for (const auto &record_type : record_types)
             values.emplace_back("(SELECT " + journal_id + ", \'" + tag + "\', \'" + subfield_code + "\', NULL, \'"
                                 + record_type + "\', \'"  + field_presence + "\')");

    return std::string("INSERT INTO metadata_presence_tracer ") +
                       "SELECT * FROM (" + StringUtil::Join(values, " UNION ALL ") + ") AS tmp " +
                       "WHERE NOT EXISTS(SELECT 1 FROM metadata_presence_tracer WHERE journal_id=" + journal_id
                                       + " AND marc_field_tag=" + tag + " LIMIT 1);";
}

void LoadHarvesterConfig(const std::string &config_path,
                         std::vector<std::unique_ptr<Config::JournalParams>> * const journal_params)
{
    std::unique_ptr<Config::GlobalParams> global_params;
    std::vector<std::unique_ptr<Config::GroupParams>> group_params;
    Config::LoadHarvesterConfigFile(config_path,
                                    &global_params,
                                    &group_params,
                                    journal_params);
}

std::string GetJournalId(DbConnection * const db_connection, const std::string &zeder_id, const std::string &group) {
    db_connection->queryOrDie("SELECT id FROM zeder_journals WHERE zeder_id=\'" + zeder_id +
                              "\' AND zeder_instance=\'" + group + "\'");
    DbResultSet result_set(db_connection->getLastResultSet());
    if (result_set.size() != 1)
        LOG_ERROR("Unable to uniquely determine journal_id for zeder_id " + zeder_id + " and group " + group);
    return result_set.getNextRow()["id"];
}

void UpdateRules(DbConnection * const db_connection, const std::vector<std::unique_ptr<Config::JournalParams>> &journal_params) {
    for (const auto &journal : journal_params)
         if (journal->selective_evaluation_) {
             const std::string journal_id(GetJournalId(db_connection, std::to_string(journal->zeder_id_),
                                          StringUtil::ASCIIToLower(journal->group_)));
             db_connection->queryOrDie(AssembleValaditionRulesIfNotExist(journal_id));
         }
}

} // unnamed namespace

int Main(int argc, char *argv[]) {
    if (argc != 2)
        Usage();

    const std::string config_path(argv[1]);
    std::vector<std::unique_ptr<Config::JournalParams>> journal_params;
    LoadHarvesterConfig(config_path, &journal_params);
    DbConnection db_connection;
    UpdateRules(&db_connection, journal_params);
    return EXIT_SUCCESS;
}
<commit_msg>Workaround<commit_after>/** \brief Tool to adjust validation rules for journal set to selective
 *         evaluation to avoid failing QS checks for field not eligible
 *         in this context
 *  \author Johannes Riedl
 *
 *  \copyright 2021 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <iostream>
#include "Compiler.h"
#include "DbConnection.h"
#include "DbResultSet.h"
#include "DbRow.h"
#include "StringUtil.h"
#include "UBTools.h"
#include "util.h"
#include "ZoteroHarvesterConfig.h"

namespace {

using namespace ZoteroHarvester;

[[noreturn]] void Usage() {
    std::cerr << "Usage: " << ::progname << " zotero_harvester.conf\n";
    std::exit(EXIT_FAILURE);
}

std::string AssembleValaditionRulesIfNotExist(const std::string journal_id)
{
    const auto tag("084");
    const std::vector<char> subfield_codes({ 'a', '2' });
    const std::vector<std::string> record_types({"regular_article", "review"});
    std::vector<std::string> values;
    const auto field_presence("ignore");
    // The following is the logic for "Insert if not exists beforehand"
    // The SELECTs in the for loop generate anonymous tuples that are merged in an multi row table by UNION ALL
    for (const auto &subfield_code : subfield_codes)
        for (const auto &record_type : record_types)
             values.emplace_back("(SELECT " + journal_id + ", \'" + tag + "\', \'" + subfield_code + "\', NULL, \'"
                                 + record_type + "\', \'"  + field_presence + "\')");

    return std::string("INSERT INTO metadata_presence_tracer ") +
                       "SELECT * FROM (" + StringUtil::Join(values, " UNION ALL ") + ") AS tmp " +
                       "WHERE NOT EXISTS(SELECT 1 FROM metadata_presence_tracer WHERE journal_id=" + journal_id
                                       + " AND marc_field_tag=" + tag + " LIMIT 1);";
}

void LoadHarvesterConfig(const std::string &config_path,
                         std::vector<std::unique_ptr<Config::JournalParams>> * const journal_params)
{
    std::unique_ptr<Config::GlobalParams> global_params;
    std::vector<std::unique_ptr<Config::GroupParams>> group_params;
    Config::LoadHarvesterConfigFile(config_path,
                                    &global_params,
                                    &group_params,
                                    journal_params);
}

std::string GetJournalId(DbConnection * const db_connection, const std::string &zeder_id, const std::string &group) {
    db_connection->queryOrDie("SELECT id FROM zeder_journals WHERE zeder_id=\'" + zeder_id +
                              "\' AND zeder_instance=\'" + group + "\'");
    DbResultSet result_set(db_connection->getLastResultSet());
    if (not result_set.size()) {
        return "";
    }
    if (result_set.size() != 1)
        LOG_ERROR("Unable to uniquely determine journal_id for zeder_id " + zeder_id + " and group " + group);
    return result_set.getNextRow()["id"];
}

void UpdateRules(DbConnection * const db_connection, const std::vector<std::unique_ptr<Config::JournalParams>> &journal_params) {
    for (const auto &journal : journal_params)
         if (journal->selective_evaluation_) {
             const std::string journal_id(GetJournalId(db_connection, std::to_string(journal->zeder_id_),
                                          StringUtil::ASCIIToLower(journal->group_)));
             if (journal_id.empty()) {
                 LOG_WARNING("No journal_id result for zeder_id " +  std::to_string(journal->zeder_id_)
                              + " in group " + journal->group_ + " - Skipping journal");
                 continue;
             }
             db_connection->queryOrDie(AssembleValaditionRulesIfNotExist(journal_id));
         }
}

} // unnamed namespace

int Main(int argc, char *argv[]) {
    if (argc != 2)
        Usage();

    const std::string config_path(argv[1]);
    std::vector<std::unique_ptr<Config::JournalParams>> journal_params;
    LoadHarvesterConfig(config_path, &journal_params);
    DbConnection db_connection;
    UpdateRules(&db_connection, journal_params);
    return EXIT_SUCCESS;
}
<|endoftext|>