<commit_before>/* contacts.cc			KPilot
**
** Copyright (C) 2008 by Bertjan Broeksema <b.broeksema@kdemail.net>
** Copyright (C) 2008 by Jason "vanRijn" Kasper <vr@movingparts.net>
*/

/*
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU Lesser General Public License as published by
** the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program in a file called COPYING; if not, write to
** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
** MA 02110-1301, USA.
*/

/*
** Bug reports and questions can be sent to kde-pim@kde.org
*/

#include "contacts.h"

#include <akonadi/control.h>
#include <akonadi/collection.h>
#include <akonadi/itemfetchjob.h>
#include <akonadi/itemfetchscope.h>

#include "options.h"

#include "record.h"
#include "hhrecord.h"

#include "contactshhdataproxy.h"
#include "contactsakonadidataproxy.h"

using namespace Akonadi;

Contacts::Contacts( KPilotLink *o, const QVariantList &a )
 : RecordConduit( o, a, CSL1( "AddressDB" ), CSL1( "Contacts Conduit" ) )
{
}

void Contacts::loadSettings()
{
	FUNCTIONSETUP;
}

bool Contacts::initDataProxies()
{
	FUNCTIONSETUP;

	if( !fDatabase )
	{
		addSyncLogEntry( i18n( "Error: Handheld database is not loaded." ) );
		return false;
	}

	// Lets make sure that Akonadi is started.
	if ( !Control::start() )
	{
		addSyncLogEntry( i18n( "Error: Could not start Akonadi." ) );
		return false;
	}

	fHHDataProxy = new ContactsHHDataProxy( fDatabase );

	// TODO: Make the collection id configurable. For now we just hardcode the
	//       collection id. To find out which collection you can sync, use
	//       akonadiconsole->folder properties->internals.
	// Fetch all items with full payload from the root collection
	ItemFetchJob *job = new ItemFetchJob( Collection( 4 ) );
	job->fetchScope().fetchFullPayload();

	if ( job->exec() ) {
		fPCDataProxy = new ContactsAkonadiDataProxy( /* job->items() */ );
		return true;
	}

	return false;
}

bool Contacts::equal( const Record *pcRec, const HHRecord *hhRec ) const
{
	FUNCTIONSETUP;

	if( !pcRec || !hhRec )
	{
		return false;
	}

	return pcRec->equal( hhRec );
}

Record* Contacts::createPCRecord( const HHRecord *hhRec )
{
	FUNCTIONSETUP;
	//TODO: IMPLEMENT
	return 0L;
}

HHRecord* Contacts::createHHRecord( const Record *pcRec )
{
	FUNCTIONSETUP;
	//TODO: IMPLEMENT
	return 0L;
}

void Contacts::_copy( const Record *from, HHRecord *to )
{
	FUNCTIONSETUP;

	//TODO: IMPLEMENT
}

void Contacts::_copy( const HHRecord *from, Record *to  )
{
	FUNCTIONSETUP;

	//TODO: IMPLEMENT
}
<commit_msg>Do not forget to initialize the backup database.<commit_after>/* contacts.cc			KPilot
**
** Copyright (C) 2008 by Bertjan Broeksema <b.broeksema@kdemail.net>
** Copyright (C) 2008 by Jason "vanRijn" Kasper <vr@movingparts.net>
*/

/*
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU Lesser General Public License as published by
** the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program in a file called COPYING; if not, write to
** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
** MA 02110-1301, USA.
*/

/*
** Bug reports and questions can be sent to kde-pim@kde.org
*/

#include "contacts.h"

#include <akonadi/control.h>
#include <akonadi/collection.h>
#include <akonadi/itemfetchjob.h>
#include <akonadi/itemfetchscope.h>

#include "options.h"

#include "record.h"
#include "hhrecord.h"

#include "contactshhdataproxy.h"
#include "contactsakonadidataproxy.h"

using namespace Akonadi;

Contacts::Contacts( KPilotLink *o, const QVariantList &a )
 : RecordConduit( o, a, CSL1( "AddressDB" ), CSL1( "Contacts Conduit" ) )
{
}

void Contacts::loadSettings()
{
	FUNCTIONSETUP;
}

bool Contacts::initDataProxies()
{
	FUNCTIONSETUP;

	if( !fDatabase )
	{
		addSyncLogEntry( i18n( "Error: Handheld database is not loaded." ) );
		return false;
	}

	// Lets make sure that Akonadi is started.
	if ( !Control::start() )
	{
		addSyncLogEntry( i18n( "Error: Could not start Akonadi." ) );
		return false;
	}

	fHHDataProxy = new ContactsHHDataProxy( fDatabase );
	fBackupDataProxy = new ContactsHHDataProxy( fLocalDatabase );

	// TODO: Make the collection id configurable. For now we just hardcode the
	//       collection id. To find out which collection you can sync, use
	//       akonadiconsole->folder properties->internals.
	// Fetch all items with full payload from the root collection
	ItemFetchJob *job = new ItemFetchJob( Collection( 4 ) );
	job->fetchScope().fetchFullPayload();

	if ( job->exec() ) {
		fPCDataProxy = new ContactsAkonadiDataProxy( /* job->items() */ );
		return true;
	}

	return false;
}

bool Contacts::equal( const Record *pcRec, const HHRecord *hhRec ) const
{
	FUNCTIONSETUP;

	if( !pcRec || !hhRec )
	{
		return false;
	}

	return pcRec->equal( hhRec );
}

Record* Contacts::createPCRecord( const HHRecord *hhRec )
{
	FUNCTIONSETUP;
	//TODO: IMPLEMENT
	return 0L;
}

HHRecord* Contacts::createHHRecord( const Record *pcRec )
{
	FUNCTIONSETUP;
	//TODO: IMPLEMENT
	return 0L;
}

void Contacts::_copy( const Record *from, HHRecord *to )
{
	FUNCTIONSETUP;

	//TODO: IMPLEMENT
}

void Contacts::_copy( const HHRecord *from, Record *to  )
{
	FUNCTIONSETUP;

	//TODO: IMPLEMENT
}
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/renderer/render_widget_fullscreen_pepper.h"

#include "base/message_loop.h"
#include "content/common/view_messages.h"
#include "content/renderer/renderer_gl_context.h"
#include "content/renderer/gpu_channel_host.h"
#include "content/renderer/pepper_platform_context_3d_impl.h"
#include "content/renderer/render_thread.h"
#include "gpu/command_buffer/client/gles2_implementation.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebSize.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebWidget.h"
#include "webkit/plugins/ppapi/plugin_delegate.h"
#include "webkit/plugins/ppapi/ppapi_plugin_instance.h"

using WebKit::WebCanvas;
using WebKit::WebCompositionUnderline;
using WebKit::WebCursorInfo;
using WebKit::WebInputEvent;
using WebKit::WebMouseEvent;
using WebKit::WebPoint;
using WebKit::WebRect;
using WebKit::WebSize;
using WebKit::WebString;
using WebKit::WebTextDirection;
using WebKit::WebTextInputType;
using WebKit::WebVector;
using WebKit::WebWidget;

namespace {

// WebWidget that simply wraps the pepper plugin.
class PepperWidget : public WebWidget {
 public:
  PepperWidget(webkit::ppapi::PluginInstance* plugin,
               RenderWidgetFullscreenPepper* widget)
      : plugin_(plugin),
        widget_(widget),
        cursor_(WebCursorInfo::TypePointer) {
  }

  // WebWidget API
  virtual void close() {
    delete this;
  }

  virtual WebSize size() {
    return size_;
  }

  virtual void resize(const WebSize& size) {
    size_ = size;
    WebRect plugin_rect(0, 0, size_.width, size_.height);
    plugin_->ViewChanged(plugin_rect, plugin_rect);
    widget_->Invalidate();
  }

  virtual void animate() {
  }

  virtual void layout() {
  }

  virtual void paint(WebCanvas* canvas, const WebRect& rect) {
    WebRect plugin_rect(0, 0, size_.width, size_.height);
    plugin_->Paint(canvas, plugin_rect, rect);
  }

  virtual void composite(bool finish) {
    RendererGLContext* context = widget_->context();
    DCHECK(context);
    gpu::gles2::GLES2Implementation* gl = context->GetImplementation();
    unsigned int texture = plugin_->GetBackingTextureId();
    gl->BindTexture(GL_TEXTURE_2D, texture);
    gl->DrawArrays(GL_TRIANGLES, 0, 3);
    context->SwapBuffers();
  }

  virtual void themeChanged() {
    NOTIMPLEMENTED();
  }

  virtual bool handleInputEvent(const WebInputEvent& event) {
    bool result = plugin_->HandleInputEvent(event, &cursor_);

    // For normal web pages, WebViewImpl does input event translations and
    // generates context menu events. Since we don't have a WebView, we need to
    // do the necessary translation ourselves.
    if (WebInputEvent::isMouseEventType(event.type)) {
      const WebMouseEvent& mouse_event =
          reinterpret_cast<const WebMouseEvent&>(event);
      bool send_context_menu_event = false;
      // On Mac/Linux, we handle it on mouse down.
      // On Windows, we handle it on mouse up.
#if defined(OS_WIN)
      send_context_menu_event =
          mouse_event.type == WebInputEvent::MouseUp &&
          mouse_event.button == WebMouseEvent::ButtonRight;
#elif defined(OS_MACOSX)
      send_context_menu_event =
          mouse_event.type == WebInputEvent::MouseDown &&
          (mouse_event.button == WebMouseEvent::ButtonRight ||
           (mouse_event.button == WebMouseEvent::ButtonLeft &&
            mouse_event.modifiers & WebMouseEvent::ControlKey));
#else
      send_context_menu_event =
          mouse_event.type == WebInputEvent::MouseDown &&
          mouse_event.button == WebMouseEvent::ButtonRight;
#endif
      if (send_context_menu_event) {
        WebMouseEvent context_menu_event(mouse_event);
        context_menu_event.type = WebInputEvent::ContextMenu;
        plugin_->HandleInputEvent(context_menu_event, &cursor_);
      }
    }
    return result;
  }

  virtual void mouseCaptureLost() {
    NOTIMPLEMENTED();
  }

  virtual void setFocus(bool focus) {
    NOTIMPLEMENTED();
  }

  // TODO(piman): figure out IME and implement these if necessary.
  virtual bool setComposition(
      const WebString& text,
      const WebVector<WebCompositionUnderline>& underlines,
      int selectionStart,
      int selectionEnd) {
    return false;
  }

  virtual bool confirmComposition() {
    return false;
  }

  virtual bool confirmComposition(const WebString& text) {
    return false;
  }

  virtual WebTextInputType textInputType() {
    return WebKit::WebTextInputTypeNone;
  }

  virtual WebRect caretOrSelectionBounds() {
    return WebRect();
  }

  virtual bool selectionRange(WebPoint& start, WebPoint& end) const {
    return false;
  }

  virtual void setTextDirection(WebTextDirection) {
  }

  virtual bool isAcceleratedCompositingActive() const {
    return widget_->context() && (plugin_->GetBackingTextureId() != 0);
  }

 private:
  scoped_refptr<webkit::ppapi::PluginInstance> plugin_;
  RenderWidgetFullscreenPepper* widget_;
  WebSize size_;
  WebCursorInfo cursor_;

  DISALLOW_COPY_AND_ASSIGN(PepperWidget);
};

void DestroyContext(RendererGLContext* context, GLuint program, GLuint buffer) {
  DCHECK(context);
  gpu::gles2::GLES2Implementation* gl = context->GetImplementation();
  if (program)
    gl->DeleteProgram(program);
  if (buffer)
    gl->DeleteBuffers(1, &buffer);
  delete context;
}

}  // anonymous namespace

// static
RenderWidgetFullscreenPepper* RenderWidgetFullscreenPepper::Create(
    int32 opener_id, RenderThreadBase* render_thread,
    webkit::ppapi::PluginInstance* plugin,
    const GURL& active_url) {
  DCHECK_NE(MSG_ROUTING_NONE, opener_id);
  scoped_refptr<RenderWidgetFullscreenPepper> widget(
      new RenderWidgetFullscreenPepper(render_thread, plugin, active_url));
  widget->Init(opener_id);
  return widget.release();
}

RenderWidgetFullscreenPepper::RenderWidgetFullscreenPepper(
    RenderThreadBase* render_thread,
    webkit::ppapi::PluginInstance* plugin,
    const GURL& active_url)
    : RenderWidgetFullscreen(render_thread),
      active_url_(active_url),
      plugin_(plugin),
      context_(NULL),
      buffer_(0),
      program_(0) {
}

RenderWidgetFullscreenPepper::~RenderWidgetFullscreenPepper() {
  if (context_)
    DestroyContext(context_, program_, buffer_);
}

void RenderWidgetFullscreenPepper::Invalidate() {
  InvalidateRect(gfx::Rect(size_.width(), size_.height()));
}

void RenderWidgetFullscreenPepper::InvalidateRect(const WebKit::WebRect& rect) {
  if (CheckCompositing()) {
    scheduleComposite();
  } else {
    didInvalidateRect(rect);
  }
}

void RenderWidgetFullscreenPepper::ScrollRect(
    int dx, int dy, const WebKit::WebRect& rect) {
  if (CheckCompositing()) {
    scheduleComposite();
  } else {
    didScrollRect(dx, dy, rect);
  }
}

void RenderWidgetFullscreenPepper::Destroy() {
  // This function is called by the plugin instance as it's going away, so reset
  // plugin_ to NULL to avoid calling into a dangling pointer e.g. on Close().
  plugin_ = NULL;
  Send(new ViewHostMsg_Close(routing_id_));
}

webkit::ppapi::PluginDelegate::PlatformContext3D*
RenderWidgetFullscreenPepper::CreateContext3D() {
  if (!context_) {
    CreateContext();
  }
  if (!context_)
    return NULL;
  return new PlatformContext3DImpl(context_);
}

void RenderWidgetFullscreenPepper::DidInitiatePaint() {
  if (plugin_)
    plugin_->ViewInitiatedPaint();
}

void RenderWidgetFullscreenPepper::DidFlushPaint() {
  if (plugin_)
    plugin_->ViewFlushedPaint();
}

void RenderWidgetFullscreenPepper::Close() {
  // If the fullscreen window is closed (e.g. user pressed escape), reset to
  // normal mode.
  if (plugin_)
    plugin_->SetFullscreen(false, false);
}

webkit::ppapi::PluginInstance*
RenderWidgetFullscreenPepper::GetBitmapForOptimizedPluginPaint(
    const gfx::Rect& paint_bounds,
    TransportDIB** dib,
    gfx::Rect* location,
    gfx::Rect* clip) {
  if (plugin_ &&
      plugin_->GetBitmapForOptimizedPluginPaint(paint_bounds, dib,
                                                location, clip))
    return plugin_;
  return NULL;
}

void RenderWidgetFullscreenPepper::OnResize(const gfx::Size& size,
                                            const gfx::Rect& resizer_rect) {
  if (context_) {
    gpu::gles2::GLES2Implementation* gl = context_->GetImplementation();
#if defined(OS_MACOSX)
    context_->ResizeOnscreen(size);
#else
    gl->ResizeCHROMIUM(size.width(), size.height());
#endif
    gl->Viewport(0, 0, size.width(), size.height());
  }
  RenderWidget::OnResize(size, resizer_rect);
}

WebWidget* RenderWidgetFullscreenPepper::CreateWebWidget() {
  return new PepperWidget(plugin_, this);
}

void RenderWidgetFullscreenPepper::CreateContext() {
  DCHECK(!context_);
  RenderThread* render_thread = RenderThread::current();
  DCHECK(render_thread);
  GpuChannelHost* host = render_thread->EstablishGpuChannelSync(
    content::CAUSE_FOR_GPU_LAUNCH_RENDERWIDGETFULLSCREENPEPPER_CREATECONTEXT);
  if (!host)
    return;
  const int32 attribs[] = {
    RendererGLContext::ALPHA_SIZE, 8,
    RendererGLContext::DEPTH_SIZE, 0,
    RendererGLContext::STENCIL_SIZE, 0,
    RendererGLContext::SAMPLES, 0,
    RendererGLContext::SAMPLE_BUFFERS, 0,
    RendererGLContext::NONE,
  };
  context_ = RendererGLContext::CreateViewContext(
      host,
      compositing_surface(),
      routing_id(),
      "GL_OES_packed_depth_stencil GL_OES_depth24",
      attribs,
      active_url_);
  if (!context_)
    return;

  if (!InitContext()) {
    DestroyContext(context_, program_, buffer_);
    context_ = NULL;
    return;
  }
  context_->SetSwapBuffersCallback(
      NewCallback(this, &RenderWidgetFullscreenPepper::DidFlushPaint));
  context_->SetContextLostCallback(
      NewCallback(this, &RenderWidgetFullscreenPepper::OnLostContext));
}

namespace {

const char kVertexShader[] =
    "attribute vec2 in_tex_coord;\n"
    "varying vec2 tex_coord;\n"
    "void main() {\n"
    "  gl_Position = vec4(in_tex_coord.x * 2. - 1.,\n"
    "                     in_tex_coord.y * 2. - 1.,\n"
    "                     0.,\n"
    "                     1.);\n"
    "  tex_coord = vec2(in_tex_coord.x, in_tex_coord.y);\n"
    "}\n";

const char kFragmentShader[] =
    "precision mediump float;\n"
    "varying vec2 tex_coord;\n"
    "uniform sampler2D in_texture;\n"
    "void main() {\n"
    "  gl_FragColor = texture2D(in_texture, tex_coord);\n"
    "}\n";

GLuint CreateShaderFromSource(gpu::gles2::GLES2Implementation* gl,
                              GLenum type,
                              const char* source) {
    GLuint shader = gl->CreateShader(type);
    gl->ShaderSource(shader, 1, &source, NULL);
    gl->CompileShader(shader);
    int status;
    gl->GetShaderiv(shader, GL_COMPILE_STATUS, &status);
    if (!status) {
        int size = 0;
        gl->GetShaderiv(shader, GL_INFO_LOG_LENGTH, &size);
        scoped_array<char> log(new char[size]);
        gl->GetShaderInfoLog(shader, size, NULL, log.get());
        DLOG(ERROR) << "Compilation failed: " << log.get();
        gl->DeleteShader(shader);
        shader = 0;
    }
    return shader;
}

const float kTexCoords[] = {
    0.f, 0.f,
    0.f, 2.f,
    2.f, 0.f,
};

}  // anonymous namespace

bool RenderWidgetFullscreenPepper::InitContext() {
  gpu::gles2::GLES2Implementation* gl = context_->GetImplementation();
  program_ = gl->CreateProgram();

  GLuint vertex_shader =
      CreateShaderFromSource(gl, GL_VERTEX_SHADER, kVertexShader);
  if (!vertex_shader)
    return false;
  gl->AttachShader(program_, vertex_shader);
  gl->DeleteShader(vertex_shader);

  GLuint fragment_shader =
      CreateShaderFromSource(gl, GL_FRAGMENT_SHADER, kFragmentShader);
  if (!fragment_shader)
    return false;
  gl->AttachShader(program_, fragment_shader);
  gl->DeleteShader(fragment_shader);

  gl->BindAttribLocation(program_, 0, "in_tex_coord");
  gl->LinkProgram(program_);
  int status;
  gl->GetProgramiv(program_, GL_LINK_STATUS, &status);
  if (!status) {
    int size = 0;
    gl->GetProgramiv(program_, GL_INFO_LOG_LENGTH, &size);
    scoped_array<char> log(new char[size]);
    gl->GetProgramInfoLog(program_, size, NULL, log.get());
    DLOG(ERROR) << "Link failed: " << log.get();
    return false;
  }
  gl->UseProgram(program_);
  int texture_location = gl->GetUniformLocation(program_, "in_texture");
  gl->Uniform1i(texture_location, 0);

  gl->GenBuffers(1, &buffer_);
  gl->BindBuffer(GL_ARRAY_BUFFER, buffer_);
  gl->BufferData(GL_ARRAY_BUFFER,
                 sizeof(kTexCoords),
                 kTexCoords,
                 GL_STATIC_DRAW);
  gl->VertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
  gl->EnableVertexAttribArray(0);
  return true;
}

bool RenderWidgetFullscreenPepper::CheckCompositing() {
  bool compositing = webwidget_->isAcceleratedCompositingActive();
  if (compositing != is_accelerated_compositing_active_) {
    didActivateAcceleratedCompositing(compositing);
  }
  return compositing;
}

void RenderWidgetFullscreenPepper::OnLostContext() {
  if (!context_)
    return;
  // Destroy the context later, in case we got called from InitContext for
  // example. We still need to reset context_ now so that a new context gets
  // created when the plugin recreates its own.
  MessageLoop::current()->PostTask(
      FROM_HERE,
      NewRunnableFunction(DestroyContext, context_, program_, buffer_));
  context_ = NULL;
  program_ = 0;
  buffer_ = 0;
}
<commit_msg>fix compile failure resulting from webkit r85001 - provide default stub<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/renderer/render_widget_fullscreen_pepper.h"

#include "base/message_loop.h"
#include "content/common/view_messages.h"
#include "content/renderer/renderer_gl_context.h"
#include "content/renderer/gpu_channel_host.h"
#include "content/renderer/pepper_platform_context_3d_impl.h"
#include "content/renderer/render_thread.h"
#include "gpu/command_buffer/client/gles2_implementation.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebSize.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebWidget.h"
#include "webkit/plugins/ppapi/plugin_delegate.h"
#include "webkit/plugins/ppapi/ppapi_plugin_instance.h"

using WebKit::WebCanvas;
using WebKit::WebCompositionUnderline;
using WebKit::WebCursorInfo;
using WebKit::WebInputEvent;
using WebKit::WebMouseEvent;
using WebKit::WebPoint;
using WebKit::WebRect;
using WebKit::WebSize;
using WebKit::WebString;
using WebKit::WebTextDirection;
using WebKit::WebTextInputType;
using WebKit::WebVector;
using WebKit::WebWidget;

namespace {

// WebWidget that simply wraps the pepper plugin.
class PepperWidget : public WebWidget {
 public:
  PepperWidget(webkit::ppapi::PluginInstance* plugin,
               RenderWidgetFullscreenPepper* widget)
      : plugin_(plugin),
        widget_(widget),
        cursor_(WebCursorInfo::TypePointer) {
  }

  // WebWidget API
  virtual void close() {
    delete this;
  }

  virtual WebSize size() {
    return size_;
  }

  virtual void resize(const WebSize& size) {
    size_ = size;
    WebRect plugin_rect(0, 0, size_.width, size_.height);
    plugin_->ViewChanged(plugin_rect, plugin_rect);
    widget_->Invalidate();
  }

  virtual void animate() {
  }

  virtual void layout() {
  }

  virtual void paint(WebCanvas* canvas, const WebRect& rect) {
    WebRect plugin_rect(0, 0, size_.width, size_.height);
    plugin_->Paint(canvas, plugin_rect, rect);
  }

  virtual void composite(bool finish) {
    RendererGLContext* context = widget_->context();
    DCHECK(context);
    gpu::gles2::GLES2Implementation* gl = context->GetImplementation();
    unsigned int texture = plugin_->GetBackingTextureId();
    gl->BindTexture(GL_TEXTURE_2D, texture);
    gl->DrawArrays(GL_TRIANGLES, 0, 3);
    context->SwapBuffers();
  }

  virtual void themeChanged() {
    NOTIMPLEMENTED();
  }

  virtual bool handleInputEvent(const WebInputEvent& event) {
    bool result = plugin_->HandleInputEvent(event, &cursor_);

    // For normal web pages, WebViewImpl does input event translations and
    // generates context menu events. Since we don't have a WebView, we need to
    // do the necessary translation ourselves.
    if (WebInputEvent::isMouseEventType(event.type)) {
      const WebMouseEvent& mouse_event =
          reinterpret_cast<const WebMouseEvent&>(event);
      bool send_context_menu_event = false;
      // On Mac/Linux, we handle it on mouse down.
      // On Windows, we handle it on mouse up.
#if defined(OS_WIN)
      send_context_menu_event =
          mouse_event.type == WebInputEvent::MouseUp &&
          mouse_event.button == WebMouseEvent::ButtonRight;
#elif defined(OS_MACOSX)
      send_context_menu_event =
          mouse_event.type == WebInputEvent::MouseDown &&
          (mouse_event.button == WebMouseEvent::ButtonRight ||
           (mouse_event.button == WebMouseEvent::ButtonLeft &&
            mouse_event.modifiers & WebMouseEvent::ControlKey));
#else
      send_context_menu_event =
          mouse_event.type == WebInputEvent::MouseDown &&
          mouse_event.button == WebMouseEvent::ButtonRight;
#endif
      if (send_context_menu_event) {
        WebMouseEvent context_menu_event(mouse_event);
        context_menu_event.type = WebInputEvent::ContextMenu;
        plugin_->HandleInputEvent(context_menu_event, &cursor_);
      }
    }
    return result;
  }

  virtual void mouseCaptureLost() {
    NOTIMPLEMENTED();
  }

  virtual void setFocus(bool focus) {
    NOTIMPLEMENTED();
  }

  // TODO(piman): figure out IME and implement these if necessary.
  virtual bool setComposition(
      const WebString& text,
      const WebVector<WebCompositionUnderline>& underlines,
      int selectionStart,
      int selectionEnd) {
    return false;
  }

  virtual bool confirmComposition() {
    return false;
  }

  virtual bool compositionRange(size_t* location, size_t* length) {
    return false;
  }

  virtual bool confirmComposition(const WebString& text) {
    return false;
  }

  virtual WebTextInputType textInputType() {
    return WebKit::WebTextInputTypeNone;
  }

  virtual WebRect caretOrSelectionBounds() {
    return WebRect();
  }

  virtual bool selectionRange(WebPoint& start, WebPoint& end) const {
    return false;
  }

  virtual bool selectionRange(size_t *location, size_t *length) {
    return false;
  }

  virtual void setTextDirection(WebTextDirection) {
  }

  virtual bool isAcceleratedCompositingActive() const {
    return widget_->context() && (plugin_->GetBackingTextureId() != 0);
  }

 private:
  scoped_refptr<webkit::ppapi::PluginInstance> plugin_;
  RenderWidgetFullscreenPepper* widget_;
  WebSize size_;
  WebCursorInfo cursor_;

  DISALLOW_COPY_AND_ASSIGN(PepperWidget);
};

void DestroyContext(RendererGLContext* context, GLuint program, GLuint buffer) {
  DCHECK(context);
  gpu::gles2::GLES2Implementation* gl = context->GetImplementation();
  if (program)
    gl->DeleteProgram(program);
  if (buffer)
    gl->DeleteBuffers(1, &buffer);
  delete context;
}

}  // anonymous namespace

// static
RenderWidgetFullscreenPepper* RenderWidgetFullscreenPepper::Create(
    int32 opener_id, RenderThreadBase* render_thread,
    webkit::ppapi::PluginInstance* plugin,
    const GURL& active_url) {
  DCHECK_NE(MSG_ROUTING_NONE, opener_id);
  scoped_refptr<RenderWidgetFullscreenPepper> widget(
      new RenderWidgetFullscreenPepper(render_thread, plugin, active_url));
  widget->Init(opener_id);
  return widget.release();
}

RenderWidgetFullscreenPepper::RenderWidgetFullscreenPepper(
    RenderThreadBase* render_thread,
    webkit::ppapi::PluginInstance* plugin,
    const GURL& active_url)
    : RenderWidgetFullscreen(render_thread),
      active_url_(active_url),
      plugin_(plugin),
      context_(NULL),
      buffer_(0),
      program_(0) {
}

RenderWidgetFullscreenPepper::~RenderWidgetFullscreenPepper() {
  if (context_)
    DestroyContext(context_, program_, buffer_);
}

void RenderWidgetFullscreenPepper::Invalidate() {
  InvalidateRect(gfx::Rect(size_.width(), size_.height()));
}

void RenderWidgetFullscreenPepper::InvalidateRect(const WebKit::WebRect& rect) {
  if (CheckCompositing()) {
    scheduleComposite();
  } else {
    didInvalidateRect(rect);
  }
}

void RenderWidgetFullscreenPepper::ScrollRect(
    int dx, int dy, const WebKit::WebRect& rect) {
  if (CheckCompositing()) {
    scheduleComposite();
  } else {
    didScrollRect(dx, dy, rect);
  }
}

void RenderWidgetFullscreenPepper::Destroy() {
  // This function is called by the plugin instance as it's going away, so reset
  // plugin_ to NULL to avoid calling into a dangling pointer e.g. on Close().
  plugin_ = NULL;
  Send(new ViewHostMsg_Close(routing_id_));
}

webkit::ppapi::PluginDelegate::PlatformContext3D*
RenderWidgetFullscreenPepper::CreateContext3D() {
  if (!context_) {
    CreateContext();
  }
  if (!context_)
    return NULL;
  return new PlatformContext3DImpl(context_);
}

void RenderWidgetFullscreenPepper::DidInitiatePaint() {
  if (plugin_)
    plugin_->ViewInitiatedPaint();
}

void RenderWidgetFullscreenPepper::DidFlushPaint() {
  if (plugin_)
    plugin_->ViewFlushedPaint();
}

void RenderWidgetFullscreenPepper::Close() {
  // If the fullscreen window is closed (e.g. user pressed escape), reset to
  // normal mode.
  if (plugin_)
    plugin_->SetFullscreen(false, false);
}

webkit::ppapi::PluginInstance*
RenderWidgetFullscreenPepper::GetBitmapForOptimizedPluginPaint(
    const gfx::Rect& paint_bounds,
    TransportDIB** dib,
    gfx::Rect* location,
    gfx::Rect* clip) {
  if (plugin_ &&
      plugin_->GetBitmapForOptimizedPluginPaint(paint_bounds, dib,
                                                location, clip))
    return plugin_;
  return NULL;
}

void RenderWidgetFullscreenPepper::OnResize(const gfx::Size& size,
                                            const gfx::Rect& resizer_rect) {
  if (context_) {
    gpu::gles2::GLES2Implementation* gl = context_->GetImplementation();
#if defined(OS_MACOSX)
    context_->ResizeOnscreen(size);
#else
    gl->ResizeCHROMIUM(size.width(), size.height());
#endif
    gl->Viewport(0, 0, size.width(), size.height());
  }
  RenderWidget::OnResize(size, resizer_rect);
}

WebWidget* RenderWidgetFullscreenPepper::CreateWebWidget() {
  return new PepperWidget(plugin_, this);
}

void RenderWidgetFullscreenPepper::CreateContext() {
  DCHECK(!context_);
  RenderThread* render_thread = RenderThread::current();
  DCHECK(render_thread);
  GpuChannelHost* host = render_thread->EstablishGpuChannelSync(
    content::CAUSE_FOR_GPU_LAUNCH_RENDERWIDGETFULLSCREENPEPPER_CREATECONTEXT);
  if (!host)
    return;
  const int32 attribs[] = {
    RendererGLContext::ALPHA_SIZE, 8,
    RendererGLContext::DEPTH_SIZE, 0,
    RendererGLContext::STENCIL_SIZE, 0,
    RendererGLContext::SAMPLES, 0,
    RendererGLContext::SAMPLE_BUFFERS, 0,
    RendererGLContext::NONE,
  };
  context_ = RendererGLContext::CreateViewContext(
      host,
      compositing_surface(),
      routing_id(),
      "GL_OES_packed_depth_stencil GL_OES_depth24",
      attribs,
      active_url_);
  if (!context_)
    return;

  if (!InitContext()) {
    DestroyContext(context_, program_, buffer_);
    context_ = NULL;
    return;
  }
  context_->SetSwapBuffersCallback(
      NewCallback(this, &RenderWidgetFullscreenPepper::DidFlushPaint));
  context_->SetContextLostCallback(
      NewCallback(this, &RenderWidgetFullscreenPepper::OnLostContext));
}

namespace {

const char kVertexShader[] =
    "attribute vec2 in_tex_coord;\n"
    "varying vec2 tex_coord;\n"
    "void main() {\n"
    "  gl_Position = vec4(in_tex_coord.x * 2. - 1.,\n"
    "                     in_tex_coord.y * 2. - 1.,\n"
    "                     0.,\n"
    "                     1.);\n"
    "  tex_coord = vec2(in_tex_coord.x, in_tex_coord.y);\n"
    "}\n";

const char kFragmentShader[] =
    "precision mediump float;\n"
    "varying vec2 tex_coord;\n"
    "uniform sampler2D in_texture;\n"
    "void main() {\n"
    "  gl_FragColor = texture2D(in_texture, tex_coord);\n"
    "}\n";

GLuint CreateShaderFromSource(gpu::gles2::GLES2Implementation* gl,
                              GLenum type,
                              const char* source) {
    GLuint shader = gl->CreateShader(type);
    gl->ShaderSource(shader, 1, &source, NULL);
    gl->CompileShader(shader);
    int status;
    gl->GetShaderiv(shader, GL_COMPILE_STATUS, &status);
    if (!status) {
        int size = 0;
        gl->GetShaderiv(shader, GL_INFO_LOG_LENGTH, &size);
        scoped_array<char> log(new char[size]);
        gl->GetShaderInfoLog(shader, size, NULL, log.get());
        DLOG(ERROR) << "Compilation failed: " << log.get();
        gl->DeleteShader(shader);
        shader = 0;
    }
    return shader;
}

const float kTexCoords[] = {
    0.f, 0.f,
    0.f, 2.f,
    2.f, 0.f,
};

}  // anonymous namespace

bool RenderWidgetFullscreenPepper::InitContext() {
  gpu::gles2::GLES2Implementation* gl = context_->GetImplementation();
  program_ = gl->CreateProgram();

  GLuint vertex_shader =
      CreateShaderFromSource(gl, GL_VERTEX_SHADER, kVertexShader);
  if (!vertex_shader)
    return false;
  gl->AttachShader(program_, vertex_shader);
  gl->DeleteShader(vertex_shader);

  GLuint fragment_shader =
      CreateShaderFromSource(gl, GL_FRAGMENT_SHADER, kFragmentShader);
  if (!fragment_shader)
    return false;
  gl->AttachShader(program_, fragment_shader);
  gl->DeleteShader(fragment_shader);

  gl->BindAttribLocation(program_, 0, "in_tex_coord");
  gl->LinkProgram(program_);
  int status;
  gl->GetProgramiv(program_, GL_LINK_STATUS, &status);
  if (!status) {
    int size = 0;
    gl->GetProgramiv(program_, GL_INFO_LOG_LENGTH, &size);
    scoped_array<char> log(new char[size]);
    gl->GetProgramInfoLog(program_, size, NULL, log.get());
    DLOG(ERROR) << "Link failed: " << log.get();
    return false;
  }
  gl->UseProgram(program_);
  int texture_location = gl->GetUniformLocation(program_, "in_texture");
  gl->Uniform1i(texture_location, 0);

  gl->GenBuffers(1, &buffer_);
  gl->BindBuffer(GL_ARRAY_BUFFER, buffer_);
  gl->BufferData(GL_ARRAY_BUFFER,
                 sizeof(kTexCoords),
                 kTexCoords,
                 GL_STATIC_DRAW);
  gl->VertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
  gl->EnableVertexAttribArray(0);
  return true;
}

bool RenderWidgetFullscreenPepper::CheckCompositing() {
  bool compositing = webwidget_->isAcceleratedCompositingActive();
  if (compositing != is_accelerated_compositing_active_) {
    didActivateAcceleratedCompositing(compositing);
  }
  return compositing;
}

void RenderWidgetFullscreenPepper::OnLostContext() {
  if (!context_)
    return;
  // Destroy the context later, in case we got called from InitContext for
  // example. We still need to reset context_ now so that a new context gets
  // created when the plugin recreates its own.
  MessageLoop::current()->PostTask(
      FROM_HERE,
      NewRunnableFunction(DestroyContext, context_, program_, buffer_));
  context_ = NULL;
  program_ = 0;
  buffer_ = 0;
}
<|endoftext|>


<commit_before>// Copyright (C) 2010-2014 Joshua Boyce.
// See the file COPYING for copying permission.

#include "radar.hpp"

#include <d3d11.h>

#include <algorithm>
#include <cstdint>
#include <fstream>

#include <hadesmem/config.hpp>
#include <hadesmem/detail/trace.hpp>
#include <hadesmem/error.hpp>

#include "root_window.hpp"

namespace
{
std::size_t g_on_frame_callback_id{static_cast<std::uint32_t>(-1)};

void UpdateRadar(void* /*base*/)
{
  auto const hwnd = GetWindowHandle();
  if (!hwnd || !GetRadarEnabled())
  {
    return;
  }

  static RadarData radar_data;
  radar_data.player_ = {{200, 100, 100}, 0};
  radar_data.units_.emplace_back(
    RadarData::UnitData{Vec3f{250, 150, 50}, RGB(255, 0, 0), "Cat"});
  radar_data.units_.emplace_back(
    RadarData::UnitData{Vec3f{200, 50, 150}, RGB(0, 255, 0), "Dog"});
  radar_data.units_.emplace_back(
    RadarData::UnitData{Vec3f{125, 0, 75}, RGB(0, 0, 255), "raptorfactor"});
  radar_data.units_.emplace_back(RadarData::UnitData{
    Vec3f{150, -50, 150}, RGB(255, 255, 0), "Sir Herpington of Derpingsworth"});
  radar_data.units_.emplace_back(
    RadarData::UnitData{Vec3f{175, -150, 25}, RGB(0, 255, 255), "Foo"});

  PostMessageW(
    hwnd, WM_APP_UPDATE_RADAR, reinterpret_cast<WPARAM>(&radar_data), 0);

  std::unique_lock<std::mutex> lock(GetRadarFrameMutex());
  auto& radar_frame_processed = GetRadarFrameProcessed();
  while (!radar_frame_processed)
  {
    GetRadarFrameConditionVariable().wait(lock);
  }

  radar_frame_processed = false;
}

void OnFrame(IDXGISwapChain* /*swap_chain*/)
{
  static auto const base = GetModuleHandleW(nullptr);

  static std::uint64_t frames{};
  if (frames++ % 30)
  {
    UpdateRadar(base);
  }
}
}

void InitializeRadar(hadesmem::cerberus::PluginInterface* cerberus)
{
  HADESMEM_DETAIL_TRACE_A("Initializing.");

  g_on_frame_callback_id =
    cerberus->GetD3D11Interface()->RegisterOnFrameCallback(OnFrame);
}

void CleanupRadar(hadesmem::cerberus::PluginInterface* cerberus)
{
  HADESMEM_DETAIL_TRACE_A("Cleaning up.");

  if (g_on_frame_callback_id != static_cast<std::uint32_t>(-1))
  {
    cerberus->GetD3D11Interface()->UnregisterOnFrameCallback(
      g_on_frame_callback_id);
    g_on_frame_callback_id = static_cast<std::uint32_t>(-1);
  }
}
<commit_msg>* [Cerberus] Add the functions I forgot to implement.<commit_after>// Copyright (C) 2010-2014 Joshua Boyce.
// See the file COPYING for copying permission.

#include "radar.hpp"

#include <d3d11.h>

#include <algorithm>
#include <cstdint>
#include <fstream>

#include <hadesmem/config.hpp>
#include <hadesmem/detail/trace.hpp>
#include <hadesmem/error.hpp>

#include "root_window.hpp"

namespace
{
std::size_t g_on_frame_callback_id{static_cast<std::uint32_t>(-1)};

void UpdateRadar(void* /*base*/)
{
  auto const hwnd = GetWindowHandle();
  if (!hwnd || !GetRadarEnabled())
  {
    return;
  }

  static RadarData radar_data;
  radar_data.player_ = {{200, 100, 100}, 0};
  radar_data.units_.emplace_back(
    RadarData::UnitData{Vec3f{250, 150, 50}, RGB(255, 0, 0), "Cat"});
  radar_data.units_.emplace_back(
    RadarData::UnitData{Vec3f{200, 50, 150}, RGB(0, 255, 0), "Dog"});
  radar_data.units_.emplace_back(
    RadarData::UnitData{Vec3f{125, 0, 75}, RGB(0, 0, 255), "raptorfactor"});
  radar_data.units_.emplace_back(RadarData::UnitData{
    Vec3f{150, -50, 150}, RGB(255, 255, 0), "Sir Herpington of Derpingsworth"});
  radar_data.units_.emplace_back(
    RadarData::UnitData{Vec3f{175, -150, 25}, RGB(0, 255, 255), "Foo"});

  PostMessageW(
    hwnd, WM_APP_UPDATE_RADAR, reinterpret_cast<WPARAM>(&radar_data), 0);

  std::unique_lock<std::mutex> lock(GetRadarFrameMutex());
  auto& radar_frame_processed = GetRadarFrameProcessed();
  while (!radar_frame_processed)
  {
    GetRadarFrameConditionVariable().wait(lock);
  }

  radar_frame_processed = false;
}

void OnFrame(IDXGISwapChain* /*swap_chain*/)
{
  static auto const base = GetModuleHandleW(nullptr);

  static std::uint64_t frames{};
  if (frames++ % 30)
  {
    UpdateRadar(base);
  }
}
}

void InitializeRadar(hadesmem::cerberus::PluginInterface* cerberus)
{
  HADESMEM_DETAIL_TRACE_A("Initializing.");

  g_on_frame_callback_id =
    cerberus->GetD3D11Interface()->RegisterOnFrameCallback(OnFrame);
}

void CleanupRadar(hadesmem::cerberus::PluginInterface* cerberus)
{
  HADESMEM_DETAIL_TRACE_A("Cleaning up.");

  if (g_on_frame_callback_id != static_cast<std::uint32_t>(-1))
  {
    cerberus->GetD3D11Interface()->UnregisterOnFrameCallback(
      g_on_frame_callback_id);
    g_on_frame_callback_id = static_cast<std::uint32_t>(-1);
  }
}

std::mutex& GetRadarFrameMutex()
{
  static std::mutex radar_frame_mutex;
  return radar_frame_mutex;
}

std::condition_variable& GetRadarFrameConditionVariable()
{
  static std::condition_variable radar_frame_condition_variable;
  return radar_frame_condition_variable;
}

bool& GetRadarFrameProcessed()
{
  static bool radar_frame_processed = false;
  return radar_frame_processed;
}

bool& GetRadarEnabled()
{
  static bool radar_frame_enabled = false;
  return radar_frame_enabled;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *   Copyright (C) 2011-2017 by Paul-Louis Ageneau                       *
 *   paul-louis (at) ageneau (dot) org                                   *
 *                                                                       *
 *   This file is part of Teapotnet.                                     *
 *                                                                       *
 *   Teapotnet 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.                 *
 *                                                                       *
 *   Teapotnet 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 Teapotnet.                                       *
 *   If not, see <http://www.gnu.org/licenses/>.                         *
 *************************************************************************/

#include "tpn/board.hpp"
#include "tpn/resource.hpp"
#include "tpn/cache.hpp"
#include "tpn/html.hpp"
#include "tpn/user.hpp"
#include "tpn/store.hpp"
#include "tpn/config.hpp"

#include "pla/jsonserializer.hpp"
#include "pla/binaryserializer.hpp"
#include "pla/object.hpp"

namespace tpn
{

Board::Board(const String &name, const String &secret, const String &displayName) :
	mName(name),
	mDisplayName(displayName),
	mSecret(secret),
	mHasNew(false),
	mUnread(0)
{
	if(!mName.empty() && mName[0] == '/') mName = mName.substr(1);
	Assert(!mName.empty());

	Interface::Instance->add(urlPrefix(), this);

	const String prefix = "/mail/" + mName;

	Set<BinaryString> digests;
	Store::Instance->retrieveValue(Store::Hash(prefix), digests);

	for(auto it = digests.begin(); it != digests.end(); ++it)
	{
		//LogDebug("Board", "Retrieved digest: " + it->toString());
		if(fetch(Network::Link::Null, prefix, "/", *it, false))
			incoming(Network::Link::Null, prefix, "/", *it);
	}

	publish(prefix);
	subscribe(prefix);
}

Board::~Board(void)
{
	for(auto board : mSubBoards)
	{
		std::unique_lock<std::mutex> lock(board->mMutex);
		board->mBoards.erase(this);
	}

	Interface::Instance->remove(urlPrefix(), this);

	const String prefix = "/mail/" + mName;

	unpublish(prefix);
	unsubscribe(prefix);
}

String Board::urlPrefix(void) const
{
	std::unique_lock<std::mutex> lock(mMutex);
	return "/mail/" + mName;
}

bool Board::hasNew(void) const
{
	std::unique_lock<std::mutex> lock(mMutex);
	bool value = false;
	std::swap(mHasNew, value);
	return value;
}

int Board::unread(void) const
{
	// TODO: count unread
	return 0;
}

void Board::addSubBoard(sptr<Board> board)
{
	std::unique_lock<std::mutex> lock1(mMutex, std::defer_lock);
	std::unique_lock<std::mutex> lock2(board->mMutex, std::defer_lock);
	std::lock(lock1, lock2);

	board->mBoards.insert(this);
	mSubBoards.insert(board);
	mMails.append(board->mMails);	// copy mails
}

void Board::removeSubBoard(sptr<Board> board)
{
	std::unique_lock<std::mutex> lock1(mMutex, std::defer_lock);
	std::unique_lock<std::mutex> lock2(board->mMutex, std::defer_lock);
	std::lock(lock1, lock2);

	board->mBoards.erase(this);
	mSubBoards.erase(board);
}

bool Board::post(const Mail &mail)
{
	const String prefix = "/mail/" + mName;

	// Add to chain
	List<Mail> tmp;
	tmp.push_back(mail);
	if(!add(tmp))
		return false;

	// Issue mail
	issue(prefix, mail);
	return true;
}

bool Board::add(const List<Mail> &mails)
{
	const String prefix = "/mail/" + mName;

	// First, append to list
	appendMails(mails);

	try {
		std::unique_lock<std::mutex> lock(mMutex);

		// Write messages to temporary file
		String tempFileName = File::TempName();
		File tempFile(tempFileName, File::Truncate);
		BinarySerializer serializer(&tempFile);
		for(const Mail &m : mails)
			serializer << m;
		tempFile.close();

		// Move to cache
		Resource resource;
		Resource::Specs specs;
		specs.name = mName;
		specs.type = "mail";
		specs.secret = mSecret;
		for(auto d : mDigests)
			specs.previousDigests.emplace_back(std::move(d));	// chain other messages
		resource.cache(tempFileName, specs);

		// Retrieve digest and store it
		BinaryString digest = resource.digest();
		Store::Instance->storeValue(Store::Hash(prefix), digest, Store::Permanent);

		// Update digests
		mPreviousDigests.insertAll(mDigests);
		mDigests.clear();
		mDigests.insert(digest);
		mProcessedDigests.insert(digest);
	}
	catch(const Exception &e)
	{
		LogWarn("Board::process", String("Board post failed: ") + e.what());
		return false;
	}

	// Republish prefix
	publish(prefix);
	return true;
}

void Board::appendMails(const List<Mail> &mails)
{
	std::unique_lock<std::mutex> lock(mMutex);

	for(const Mail &m : mails)
		mMails.emplace_back(std::move(m));

	// Notify HTTP clients
	mCondition.notify_all();

	for(auto b : mBoards)
		b->appendMails(mails);
}

bool Board::anounce(const Network::Link &link, const String &prefix, const String &path, List<BinaryString> &targets)
{
	std::unique_lock<std::mutex> lock(mMutex);
	targets.clear();
	for(auto d : mDigests)
		targets.emplace_back(std::move(d));
	return !targets.empty();
}

bool Board::incoming(const Network::Link &link, const String &prefix, const String &path, const BinaryString &target)
{
	if(!fetch(link, prefix, path, target, true))
		return false;

	try {
		std::unique_lock<std::mutex> lock(mMutex);

		if(mProcessedDigests.contains(target))
			return false;

		Resource resource(target, true);	// local only (already fetched)
		if(resource.type() != "mail")
			return false;

		if(!mPreviousDigests.contains(target))
			mDigests.insert(target);	// top-level

		// Fetch previous
		List<BinaryString> previous;
		if(resource.getPreviousDigests(previous))
			for(const BinaryString &d : previous)
			{
				mDigests.erase(d);
				mPreviousDigests.insert(d);
				fetch(link, prefix, path, d, true);
			}

		// Process
		List<Mail> mails;
		Resource::Reader reader(&resource, mSecret);
		BinarySerializer serializer(&reader);
		Mail m;
		while(serializer >> m)
		{
			if(m.empty()) continue;
			mails.emplace_back(std::move(m));
		}

		mProcessedDigests.insert(target);

		lock.unlock();
		appendMails(mails);
	}
	catch(const Exception &e)
	{
		LogWarn("Board::incoming", e.what());
		return true;
	}

	return true;
}

bool Board::incoming(const Network::Link &link, const String &prefix, const String &path, const Mail &mail)
{
	List<Mail> tmp;
	tmp.push_back(mail);
	return add(tmp);
}

void Board::http(const String &prefix, Http::Request &request)
{
	Assert(!request.url.empty());

	try {
		if(request.url == "/")
		{
			if(request.method == "POST")
			{
				if(request.post.contains("message") && !request.post["message"].empty())
				{
					Mail mail;
					mail.setContent(request.post["message"]);

					if(request.post.contains("parent"))
					{
						BinaryString parent;
						request.post["parent"].extract(parent);
						mail.setParent(parent);
					}

					if(request.post.contains("attachment"))
					{
						BinaryString attachment;
						request.post["attachment"].extract(attachment);
						if(!attachment.empty())
							mail.addAttachment(attachment);
					}

					if(request.post.contains("author"))
					{
						mail.setAuthor(request.post["author"]);
					}
					else {
						sptr<User> user = getAuthenticatedUser(request);
						if(user) {
							mail.setAuthor(user->name());
							mail.sign(user->identifier(), user->privateKey());
						}
					}

					post(mail);

					Http::Response response(request, 200);
					response.send();
				}

				throw 400;
			}

			if(request.get.contains("json"))
			{
				int next = 0;
				if(request.get.contains("next"))
					request.get["next"].extract(next);

				duration timeout = milliseconds(Config::Get("request_timeout").toInt());
				if(request.get.contains("timeout"))
					timeout = seconds(request.get["timeout"].toDouble());

				List<Mail*> tmp;
				{
					std::unique_lock<std::mutex> lock(mMutex);

					if(next >= int(mMails.size()))
					{
						mCondition.wait_for(lock, std::chrono::duration<double>(timeout), [this, next]() {
							return next < int(mMails.size());
						});
					}

					for(int i = next; i < int(mMails.size()); ++i)
						tmp.push_back(&mMails[i]);

					mUnread = 0;
					mHasNew = false;
				}

				Http::Response response(request, 200);
				response.headers["Content-Type"] = "application/json";
				response.send();

				JsonSerializer json(response.stream);
				json.setOptionalOutputMode(true);
				json << tmp;
				return;
			}

			bool isPopup = request.get.contains("popup");
			bool isFrame = request.get.contains("frame");

			Http::Response response(request, 200);
			response.send();

			Html page(response.stream);

			String title;
			{
				std::unique_lock<std::mutex> lock(mMutex);
				title = (!mDisplayName.empty() ? mDisplayName : "Board " + mName);
			}

			page.header(title, isPopup || isFrame);

			if(!isFrame)
			{
				page.open("div","topmenu");
				if(isPopup) page.span(title, ".button");

// TODO: should be hidden in CSS
#ifndef ANDROID
				if(!isPopup)
				{
					String popupUrl = Http::AppendParam(request.fullUrl, "popup");
					page.raw("Popup");
				}
#endif

				page.close("div");
			}

			page.open("div", ".replypanel");

			sptr<User> user = getAuthenticatedUser(request);
			if(user)
			{
				page.javascript("var TokenMail = '"+user->generateToken("mail")+"';\n\
						var TokenDirectory = '"+user->generateToken("directory")+"';\n\
						var TokenContact = '"+user->generateToken("contact")+"';\n\
						var UrlSelector = '"+user->urlPrefix()+"/myself/files/?json';\n\
						var UrlUpload = '"+user->urlPrefix()+"/files/_upload/?json';");

				page.raw("");
			}

			page.openForm("#", "post", "boardform");
			page.textarea("input");
			page.input("hidden", "attachment");
			page.input("hidden", "attachmentname");
			page.closeForm();
			page.close("div");
			page.div("","#attachedfile.attachedfile");
			page.div("", "#fileSelector.fileselector");

			if(isPopup) page.open("div", "board");
			else page.open("div", "board.box");

			page.open("div", "mail");
			page.open("p"); page.text("No messages"); page.close("p");
			page.close("div");

			page.close("div");

			page.javascript("function post() {\n\
					var message = $(document.boardform.input).val();\n\
					var attachment = $(document.boardform.attachment).val();\n\
					if(!message) return false;\n\
					var fields = {};\n\
					fields['message'] = message;\n\
					if(attachment) fields['attachment'] = attachment;\n\
					$.post('"+prefix+request.url+"', fields)\n\
						.fail(function(jqXHR, textStatus) {\n\
							alert('The message could not be sent.');\n\
						});\n\
					$(document.boardform.input).val('');\n\
					$(document.boardform.attachment).val('');\n\
					$(document.boardform.attachmentname).val('');\n\
					$('#attachedfile').hide();\n\
				}\n\
				$(document.boardform).submit(function() {\n\
					post();\n\
					return false;\n\
				});\n\
				$(document.boardform.attachment).change(function() {\n\
					$('#attachedfile').html('');\n\
					$('#attachedfile').hide();\n\
					var filename = $(document.boardform.attachmentname).val();\n\
					if(filename != '') {\n\
						$('#attachedfile').append('');\n\
						$('#attachedfile').append(''+filename+'');\n\
						$('#attachedfile').show();\n\
					}\n\
					$(document.boardform.input).focus();\n\
					if($(document.boardform.input).val() == '') {\n\
						$(document.boardform.input).val(filename);\n\
						$(document.boardform.input).select();\n\
					}\n\
				});\n\
				$('#attachedfile').hide();");

			unsigned refreshPeriod = 2000;
			page.javascript("setMailReceiver('"+Http::AppendParam(request.fullUrl, "json")+"','#mail', "+String::number(refreshPeriod)+");");

			page.footer();
			return;
		}
	}
	catch(const Exception &e)
	{
		LogWarn("AddressBook::http", e.what());
		throw 500;
	}

	throw 404;
}

}
<commit_msg>Added hasNew flag<commit_after>/*************************************************************************
 *   Copyright (C) 2011-2017 by Paul-Louis Ageneau                       *
 *   paul-louis (at) ageneau (dot) org                                   *
 *                                                                       *
 *   This file is part of Teapotnet.                                     *
 *                                                                       *
 *   Teapotnet 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.                 *
 *                                                                       *
 *   Teapotnet 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 Teapotnet.                                       *
 *   If not, see <http://www.gnu.org/licenses/>.                         *
 *************************************************************************/

#include "tpn/board.hpp"
#include "tpn/resource.hpp"
#include "tpn/cache.hpp"
#include "tpn/html.hpp"
#include "tpn/user.hpp"
#include "tpn/store.hpp"
#include "tpn/config.hpp"

#include "pla/jsonserializer.hpp"
#include "pla/binaryserializer.hpp"
#include "pla/object.hpp"

namespace tpn
{

Board::Board(const String &name, const String &secret, const String &displayName) :
	mName(name),
	mDisplayName(displayName),
	mSecret(secret),
	mHasNew(false),
	mUnread(0)
{
	if(!mName.empty() && mName[0] == '/') mName = mName.substr(1);
	Assert(!mName.empty());

	Interface::Instance->add(urlPrefix(), this);

	const String prefix = "/mail/" + mName;

	Set<BinaryString> digests;
	Store::Instance->retrieveValue(Store::Hash(prefix), digests);

	for(auto it = digests.begin(); it != digests.end(); ++it)
	{
		//LogDebug("Board", "Retrieved digest: " + it->toString());
		if(fetch(Network::Link::Null, prefix, "/", *it, false))
			incoming(Network::Link::Null, prefix, "/", *it);
	}

	publish(prefix);
	subscribe(prefix);
}

Board::~Board(void)
{
	for(auto board : mSubBoards)
	{
		std::unique_lock<std::mutex> lock(board->mMutex);
		board->mBoards.erase(this);
	}

	Interface::Instance->remove(urlPrefix(), this);

	const String prefix = "/mail/" + mName;

	unpublish(prefix);
	unsubscribe(prefix);
}

String Board::urlPrefix(void) const
{
	std::unique_lock<std::mutex> lock(mMutex);
	return "/mail/" + mName;
}

bool Board::hasNew(void) const
{
	std::unique_lock<std::mutex> lock(mMutex);
	bool value = false;
	std::swap(mHasNew, value);
	return value;
}

int Board::unread(void) const
{
	// TODO: count unread
	return 0;
}

void Board::addSubBoard(sptr<Board> board)
{
	std::unique_lock<std::mutex> lock1(mMutex, std::defer_lock);
	std::unique_lock<std::mutex> lock2(board->mMutex, std::defer_lock);
	std::lock(lock1, lock2);

	board->mBoards.insert(this);
	mSubBoards.insert(board);
	mMails.append(board->mMails);	// copy mails
}

void Board::removeSubBoard(sptr<Board> board)
{
	std::unique_lock<std::mutex> lock1(mMutex, std::defer_lock);
	std::unique_lock<std::mutex> lock2(board->mMutex, std::defer_lock);
	std::lock(lock1, lock2);

	board->mBoards.erase(this);
	mSubBoards.erase(board);
}

bool Board::post(const Mail &mail)
{
	const String prefix = "/mail/" + mName;

	// Add to chain
	List<Mail> tmp;
	tmp.push_back(mail);
	if(!add(tmp))
		return false;

	// Issue mail
	issue(prefix, mail);
	return true;
}

bool Board::add(const List<Mail> &mails)
{
	const String prefix = "/mail/" + mName;

	// First, append to list
	appendMails(mails);

	try {
		std::unique_lock<std::mutex> lock(mMutex);

		// Write messages to temporary file
		String tempFileName = File::TempName();
		File tempFile(tempFileName, File::Truncate);
		BinarySerializer serializer(&tempFile);
		for(const Mail &m : mails)
			serializer << m;
		tempFile.close();

		// Move to cache
		Resource resource;
		Resource::Specs specs;
		specs.name = mName;
		specs.type = "mail";
		specs.secret = mSecret;
		for(auto d : mDigests)
			specs.previousDigests.emplace_back(std::move(d));	// chain other messages
		resource.cache(tempFileName, specs);

		// Retrieve digest and store it
		BinaryString digest = resource.digest();
		Store::Instance->storeValue(Store::Hash(prefix), digest, Store::Permanent);

		// Update digests
		mPreviousDigests.insertAll(mDigests);
		mDigests.clear();
		mDigests.insert(digest);
		mProcessedDigests.insert(digest);
	}
	catch(const Exception &e)
	{
		LogWarn("Board::process", String("Board post failed: ") + e.what());
		return false;
	}

	// Republish prefix
	publish(prefix);
	return true;
}

void Board::appendMails(const List<Mail> &mails)
{
	std::unique_lock<std::mutex> lock(mMutex);

	for(const Mail &m : mails)
		mMails.emplace_back(std::move(m));

	// Notify HTTP clients
	mCondition.notify_all();

	for(auto b : mBoards)
		b->appendMails(mails);
}

bool Board::anounce(const Network::Link &link, const String &prefix, const String &path, List<BinaryString> &targets)
{
	std::unique_lock<std::mutex> lock(mMutex);
	targets.clear();
	for(auto d : mDigests)
		targets.emplace_back(std::move(d));
	return !targets.empty();
}

bool Board::incoming(const Network::Link &link, const String &prefix, const String &path, const BinaryString &target)
{
	if(!fetch(link, prefix, path, target, true))
		return false;

	try {
		std::unique_lock<std::mutex> lock(mMutex);

		if(mProcessedDigests.contains(target))
			return false;

		Resource resource(target, true);	// local only (already fetched)
		if(resource.type() != "mail")
			return false;

		if(!mPreviousDigests.contains(target))
			mDigests.insert(target);	// top-level

		// Fetch previous
		List<BinaryString> previous;
		if(resource.getPreviousDigests(previous))
			for(const BinaryString &d : previous)
			{
				mDigests.erase(d);
				mPreviousDigests.insert(d);
				fetch(link, prefix, path, d, true);
			}

		// Process
		List<Mail> mails;
		Resource::Reader reader(&resource, mSecret);
		BinarySerializer serializer(&reader);
		Mail m;
		while(serializer >> m)
		{
			if(m.empty()) continue;
			mails.emplace_back(std::move(m));
		}

		mProcessedDigests.insert(target);

		lock.unlock();
		appendMails(mails);
	}
	catch(const Exception &e)
	{
		LogWarn("Board::incoming", e.what());
		return true;
	}

	return true;
}

bool Board::incoming(const Network::Link &link, const String &prefix, const String &path, const Mail &mail)
{
	List<Mail> tmp;
	tmp.push_back(mail);
	mHasNew = true;
	return add(tmp);
}

void Board::http(const String &prefix, Http::Request &request)
{
	Assert(!request.url.empty());

	try {
		if(request.url == "/")
		{
			if(request.method == "POST")
			{
				if(request.post.contains("message") && !request.post["message"].empty())
				{
					Mail mail;
					mail.setContent(request.post["message"]);

					if(request.post.contains("parent"))
					{
						BinaryString parent;
						request.post["parent"].extract(parent);
						mail.setParent(parent);
					}

					if(request.post.contains("attachment"))
					{
						BinaryString attachment;
						request.post["attachment"].extract(attachment);
						if(!attachment.empty())
							mail.addAttachment(attachment);
					}

					if(request.post.contains("author"))
					{
						mail.setAuthor(request.post["author"]);
					}
					else {
						sptr<User> user = getAuthenticatedUser(request);
						if(user) {
							mail.setAuthor(user->name());
							mail.sign(user->identifier(), user->privateKey());
						}
					}

					post(mail);

					Http::Response response(request, 200);
					response.send();
				}

				throw 400;
			}

			if(request.get.contains("json"))
			{
				int next = 0;
				if(request.get.contains("next"))
					request.get["next"].extract(next);

				duration timeout = milliseconds(Config::Get("request_timeout").toInt());
				if(request.get.contains("timeout"))
					timeout = seconds(request.get["timeout"].toDouble());

				List<Mail*> tmp;
				{
					std::unique_lock<std::mutex> lock(mMutex);

					if(next >= int(mMails.size()))
					{
						mCondition.wait_for(lock, std::chrono::duration<double>(timeout), [this, next]() {
							return next < int(mMails.size());
						});
					}

					for(int i = next; i < int(mMails.size()); ++i)
						tmp.push_back(&mMails[i]);

					mUnread = 0;
					mHasNew = false;
				}

				Http::Response response(request, 200);
				response.headers["Content-Type"] = "application/json";
				response.send();

				JsonSerializer json(response.stream);
				json.setOptionalOutputMode(true);
				json << tmp;
				return;
			}

			bool isPopup = request.get.contains("popup");
			bool isFrame = request.get.contains("frame");

			Http::Response response(request, 200);
			response.send();

			Html page(response.stream);

			String title;
			{
				std::unique_lock<std::mutex> lock(mMutex);
				title = (!mDisplayName.empty() ? mDisplayName : "Board " + mName);
			}

			page.header(title, isPopup || isFrame);

			if(!isFrame)
			{
				page.open("div","topmenu");
				if(isPopup) page.span(title, ".button");

// TODO: should be hidden in CSS
#ifndef ANDROID
				if(!isPopup)
				{
					String popupUrl = Http::AppendParam(request.fullUrl, "popup");
					page.raw("Popup");
				}
#endif

				page.close("div");
			}

			page.open("div", ".replypanel");

			sptr<User> user = getAuthenticatedUser(request);
			if(user)
			{
				page.javascript("var TokenMail = '"+user->generateToken("mail")+"';\n\
						var TokenDirectory = '"+user->generateToken("directory")+"';\n\
						var TokenContact = '"+user->generateToken("contact")+"';\n\
						var UrlSelector = '"+user->urlPrefix()+"/myself/files/?json';\n\
						var UrlUpload = '"+user->urlPrefix()+"/files/_upload/?json';");

				page.raw("");
			}

			page.openForm("#", "post", "boardform");
			page.textarea("input");
			page.input("hidden", "attachment");
			page.input("hidden", "attachmentname");
			page.closeForm();
			page.close("div");
			page.div("","#attachedfile.attachedfile");
			page.div("", "#fileSelector.fileselector");

			if(isPopup) page.open("div", "board");
			else page.open("div", "board.box");

			page.open("div", "mail");
			page.open("p"); page.text("No messages"); page.close("p");
			page.close("div");

			page.close("div");

			page.javascript("function post() {\n\
					var message = $(document.boardform.input).val();\n\
					var attachment = $(document.boardform.attachment).val();\n\
					if(!message) return false;\n\
					var fields = {};\n\
					fields['message'] = message;\n\
					if(attachment) fields['attachment'] = attachment;\n\
					$.post('"+prefix+request.url+"', fields)\n\
						.fail(function(jqXHR, textStatus) {\n\
							alert('The message could not be sent.');\n\
						});\n\
					$(document.boardform.input).val('');\n\
					$(document.boardform.attachment).val('');\n\
					$(document.boardform.attachmentname).val('');\n\
					$('#attachedfile').hide();\n\
				}\n\
				$(document.boardform).submit(function() {\n\
					post();\n\
					return false;\n\
				});\n\
				$(document.boardform.attachment).change(function() {\n\
					$('#attachedfile').html('');\n\
					$('#attachedfile').hide();\n\
					var filename = $(document.boardform.attachmentname).val();\n\
					if(filename != '') {\n\
						$('#attachedfile').append('');\n\
						$('#attachedfile').append(''+filename+'');\n\
						$('#attachedfile').show();\n\
					}\n\
					$(document.boardform.input).focus();\n\
					if($(document.boardform.input).val() == '') {\n\
						$(document.boardform.input).val(filename);\n\
						$(document.boardform.input).select();\n\
					}\n\
				});\n\
				$('#attachedfile').hide();");

			unsigned refreshPeriod = 2000;
			page.javascript("setMailReceiver('"+Http::AppendParam(request.fullUrl, "json")+"','#mail', "+String::number(refreshPeriod)+");");

			page.footer();
			return;
		}
	}
	catch(const Exception &e)
	{
		LogWarn("AddressBook::http", e.what());
		throw 500;
	}

	throw 404;
}

}
<|endoftext|>


<commit_before><commit_msg>[json] provide workaround for TStyle::fLineStyle member<commit_after><|endoftext|>


<commit_before>/*
 * opencog/atoms/execution/ExecutionOutputLink.cc
 *
 * Copyright (C) 2009, 2013, 2015 Linas Vepstas
 * 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 v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * 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 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, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <dlfcn.h>
#include <stdlib.h>

#include <opencog/atoms/base/atom_types.h>
#include <opencog/atomspace/AtomSpace.h>
#include <opencog/atoms/core/DefineLink.h>
#include <opencog/cython/PythonEval.h>
#include <opencog/guile/SchemeEval.h>

#include "ExecutionOutputLink.h"
#include "Instantiator.h"

using namespace opencog;

ExecutionOutputLink::ExecutionOutputLink(const HandleSeq& oset,
                                         TruthValuePtr tv,
                                         AttentionValuePtr av)
	: FunctionLink(EXECUTION_OUTPUT_LINK, oset, tv, av)
{
	if (2 != oset.size())
		throw SyntaxException(TRACE_INFO,
			"ExecutionOutputLink must have schema and args! Got arity=%d",
			oset.size());

	if (DEFINED_SCHEMA_NODE != oset[0]->getType() and
	    LAMBDA_LINK != oset[0]->getType() and
	    GROUNDED_SCHEMA_NODE != oset[0]->getType())
	{
		throw SyntaxException(TRACE_INFO,
			"ExecutionOutputLink must have schema! Got %s",
			oset[0]->toString().c_str());
	}

	if (LIST_LINK != oset[1]->getType())
		throw SyntaxException(TRACE_INFO,
			"ExecutionOutputLink must have args! Got %s",
			oset[1]->toString().c_str());
}

ExecutionOutputLink::ExecutionOutputLink(const Handle& schema,
                                         const Handle& args,
                                         TruthValuePtr tv,
                                         AttentionValuePtr av)
	: FunctionLink(EXECUTION_OUTPUT_LINK, schema, args, tv, av)
{
	Type stype = schema->getType();
	if (GROUNDED_SCHEMA_NODE != stype and
	    LAMBDA_LINK != stype and
	    DEFINED_SCHEMA_NODE != stype)
	{
		throw SyntaxException(TRACE_INFO,
			"ExecutionOutputLink expecting schema, got %s",
			schema->toString().c_str());
	}

	if (LIST_LINK != args->getType())
		throw SyntaxException(TRACE_INFO,
			"ExecutionOutputLink expecting args, got %s",
			args->toString().c_str());
}

ExecutionOutputLink::ExecutionOutputLink(Link& l)
	: FunctionLink(l)
{
	Type tscope = l.getType();
	if (EXECUTION_OUTPUT_LINK != tscope)
		throw SyntaxException(TRACE_INFO,
			"Expection an ExecutionOutputLink!");
}

/// execute -- execute the function defined in an ExecutionOutputLink
///
/// Each ExecutionOutputLink should have the form:
///
///     ExecutionOutputLink
///         GroundedSchemaNode "lang: func_name"
///         ListLink
///             SomeAtom
///             OtherAtom
///
/// The "lang:" should be either "scm:" for scheme, or "py:" for python.
/// This method will then invoke "func_name" on the provided ListLink
/// of arguments to the function.
///
Handle ExecutionOutputLink::execute(AtomSpace* as) const
{
	return do_execute(as, _outgoing[0], _outgoing[1]);
}

/// do_execute -- execute the SchemaNode of the ExecutionOutputLink
///
/// Expects "gsn" to be a GroundedSchemaNode or a DefinedSchemaNode
/// Expects "args" to be a ListLink
/// Executes the GroundedSchemaNode, supplying the args as argument
///
Handle ExecutionOutputLink::do_execute(AtomSpace* as,
                         const Handle& gsn, const Handle& cargs)
{
	LAZY_LOG_FINE << "Execute gsn: " << gsn->toShortString()
	              << "with arguments: " << cargs->toShortString();

	// Search for additional execution links, and execute them too.
	// We will know that happend if the returned handle differs from
	// the input handle. If the results are different, add the new
	// results to the atomspace. We need to do this, because scheme,
	// and python expects to find thier arguments in the atomspace,
	// but this is arguably broken, as it pollutes the atomspace with
	// junk that is never cleaned up.  We punt for now, but something
	// should be done about this. XXX FIXME ...
	Instantiator inst(as);
	Handle args(cargs);
	if (cargs->isLink())
	{
		std::vector<Handle> new_oset;
		bool changed = false;
		for (Handle ho : cargs->getOutgoingSet())
		{
			Handle nh(inst.execute(ho));
			// nh might be NULL if ho was a DeleteLink
			if (nullptr == nh)
			{
				changed = true;
				continue;
			}

			// Unwrap the top-most DontExecLink's.  Lower ones are left
			// untouched.  We do this as a sop for issue opencog/atomspace#704
			// but maybe we should not?
			if (DONT_EXEC_LINK == nh->getType())
			{
				nh = nh->getOutgoingAtom(0);
			}
			new_oset.emplace_back(nh);

			if (nh != ho) changed = true;
		}
		if (changed)
			args = as->add_link(LIST_LINK, new_oset);
	}

	// Get the schema name.
	const std::string& schema = NodeCast(gsn)->getName();
	// printf ("Grounded schema name: %s\n", schema.c_str());

	// At this point, we only run scheme, python schemas and functions from
    // libraries loaded at runtime.
	if (0 == schema.compare(0,4,"scm:", 4))
	{
#ifdef HAVE_GUILE
		// Be friendly, and strip leading white-space, if any.
		size_t pos = 4;
		while (' ' == schema[pos]) pos++;

		SchemeEval* applier = SchemeEval::get_evaluator(as);
		Handle h(applier->apply(schema.substr(pos), args));

		// Exceptions were already caught, before leaving guile mode,
		// so we can't rethrow.  Just throw a new exception.
		if (applier->eval_error())
			throw RuntimeException(TRACE_INFO,
			    "Failed evaluation; see logfile for stack trace.");
		return h;
#else
		throw RuntimeException(TRACE_INFO,
		    "Cannot evaluate scheme GroundedSchemaNode!");
#endif /* HAVE_GUILE */
	}

	if (0 == schema.compare(0, 3,"py:", 3))
	{
#ifdef HAVE_CYTHON
		// Be friendly, and strip leading white-space, if any.
		size_t pos = 3;
		while (' ' == schema[pos]) pos++;

		// Get a reference to the python evaluator.
		// Be sure to specify the atomspace in which the
		// evaluation is to be performed.
		PythonEval &applier = PythonEval::instance();
		Handle h = applier.apply(as, schema.substr(pos), args);

		// Return the handle
		return h;
#else
		throw RuntimeException(TRACE_INFO,
		    "Cannot evaluate python GroundedSchemaNode!");
#endif /* HAVE_CYTHON */
	}

	if (0 == schema.compare(0,4,"lib:", 4))
	{
		// Be friendly, and strip leading white-space, if any.
		size_t pos = 4;
		while (' ' == schema[pos]) pos++;

        //Get the name of the Library and Function
        //They should be sperated by a .
        std::size_t dotpos = schema.find("\\");
        if (dotpos == std::string::npos)
        {
            throw RuntimeException(TRACE_INFO,
                "LibName and FunctionName not seperated by a '\\'");
        }
        std::string libName  = schema.substr(pos,dotpos-pos);
        std::string funcName = schema.substr(dotpos+1);

        void *libHandle;
        void * tmp;
        UUID (*func)(AtomSpace* ,UUID);

        // Try and load the Library and the Function
        if ( (libHandle = dlopen(libName.c_str(), RTLD_LAZY)) == NULL ||
             (tmp       = dlsym(libHandle, funcName.c_str())) == NULL )
        {
            std::string err(dlerror());
            std::string msg = "Cannot Load function: " + funcName +" from lib: " + libName + " Error: " + err;
            throw RuntimeException(TRACE_INFO,
                msg.c_str());
        }

        // Convert the Void* pointer to the correct function Type
        func = reinterpret_cast<UUID (*)(AtomSpace *, UUID)>(tmp);

        // Execute the Function
		Handle h(func(as,args.value()));

        //Close Library after Use
        dlclose(libHandle);

        //Return the handle
		return h;
	}
	// Unkown proceedure type.
	throw RuntimeException(TRACE_INFO,
	    "Cannot evaluate unknown GroundedSchemaNode!");
}
<commit_msg>Fix bad indentation<commit_after>/*
 * opencog/atoms/execution/ExecutionOutputLink.cc
 *
 * Copyright (C) 2009, 2013, 2015 Linas Vepstas
 * 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 v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * 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 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, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <dlfcn.h>
#include <stdlib.h>

#include <opencog/atoms/base/atom_types.h>
#include <opencog/atomspace/AtomSpace.h>
#include <opencog/atoms/core/DefineLink.h>
#include <opencog/cython/PythonEval.h>
#include <opencog/guile/SchemeEval.h>

#include "ExecutionOutputLink.h"
#include "Instantiator.h"

using namespace opencog;

ExecutionOutputLink::ExecutionOutputLink(const HandleSeq& oset,
                                         TruthValuePtr tv,
                                         AttentionValuePtr av)
	: FunctionLink(EXECUTION_OUTPUT_LINK, oset, tv, av)
{
	if (2 != oset.size())
		throw SyntaxException(TRACE_INFO,
			"ExecutionOutputLink must have schema and args! Got arity=%d",
			oset.size());

	if (DEFINED_SCHEMA_NODE != oset[0]->getType() and
	    LAMBDA_LINK != oset[0]->getType() and
	    GROUNDED_SCHEMA_NODE != oset[0]->getType())
	{
		throw SyntaxException(TRACE_INFO,
			"ExecutionOutputLink must have schema! Got %s",
			oset[0]->toString().c_str());
	}

	if (LIST_LINK != oset[1]->getType())
		throw SyntaxException(TRACE_INFO,
			"ExecutionOutputLink must have args! Got %s",
			oset[1]->toString().c_str());
}

ExecutionOutputLink::ExecutionOutputLink(const Handle& schema,
                                         const Handle& args,
                                         TruthValuePtr tv,
                                         AttentionValuePtr av)
	: FunctionLink(EXECUTION_OUTPUT_LINK, schema, args, tv, av)
{
	Type stype = schema->getType();
	if (GROUNDED_SCHEMA_NODE != stype and
	    LAMBDA_LINK != stype and
	    DEFINED_SCHEMA_NODE != stype)
	{
		throw SyntaxException(TRACE_INFO,
			"ExecutionOutputLink expecting schema, got %s",
			schema->toString().c_str());
	}

	if (LIST_LINK != args->getType())
		throw SyntaxException(TRACE_INFO,
			"ExecutionOutputLink expecting args, got %s",
			args->toString().c_str());
}

ExecutionOutputLink::ExecutionOutputLink(Link& l)
	: FunctionLink(l)
{
	Type tscope = l.getType();
	if (EXECUTION_OUTPUT_LINK != tscope)
		throw SyntaxException(TRACE_INFO,
			"Expection an ExecutionOutputLink!");
}

/// execute -- execute the function defined in an ExecutionOutputLink
///
/// Each ExecutionOutputLink should have the form:
///
///     ExecutionOutputLink
///         GroundedSchemaNode "lang: func_name"
///         ListLink
///             SomeAtom
///             OtherAtom
///
/// The "lang:" should be either "scm:" for scheme, or "py:" for python.
/// This method will then invoke "func_name" on the provided ListLink
/// of arguments to the function.
///
Handle ExecutionOutputLink::execute(AtomSpace* as) const
{
	return do_execute(as, _outgoing[0], _outgoing[1]);
}

/// do_execute -- execute the SchemaNode of the ExecutionOutputLink
///
/// Expects "gsn" to be a GroundedSchemaNode or a DefinedSchemaNode
/// Expects "args" to be a ListLink
/// Executes the GroundedSchemaNode, supplying the args as argument
///
Handle ExecutionOutputLink::do_execute(AtomSpace* as,
                         const Handle& gsn, const Handle& cargs)
{
	LAZY_LOG_FINE << "Execute gsn: " << gsn->toShortString()
	              << "with arguments: " << cargs->toShortString();

	// Search for additional execution links, and execute them too.
	// We will know that happend if the returned handle differs from
	// the input handle. If the results are different, add the new
	// results to the atomspace. We need to do this, because scheme,
	// and python expects to find thier arguments in the atomspace,
	// but this is arguably broken, as it pollutes the atomspace with
	// junk that is never cleaned up.  We punt for now, but something
	// should be done about this. XXX FIXME ...
	Instantiator inst(as);
	Handle args(cargs);
	if (cargs->isLink())
	{
		std::vector<Handle> new_oset;
		bool changed = false;
		for (Handle ho : cargs->getOutgoingSet())
		{
			Handle nh(inst.execute(ho));
			// nh might be NULL if ho was a DeleteLink
			if (nullptr == nh)
			{
				changed = true;
				continue;
			}

			// Unwrap the top-most DontExecLink's.  Lower ones are left
			// untouched.  We do this as a sop for issue opencog/atomspace#704
			// but maybe we should not?
			if (DONT_EXEC_LINK == nh->getType())
			{
				nh = nh->getOutgoingAtom(0);
			}
			new_oset.emplace_back(nh);

			if (nh != ho) changed = true;
		}
		if (changed)
			args = as->add_link(LIST_LINK, new_oset);
	}

	// Get the schema name.
	const std::string& schema = NodeCast(gsn)->getName();
	// printf ("Grounded schema name: %s\n", schema.c_str());

	// At this point, we only run scheme, python schemas and functions from
	// libraries loaded at runtime.
	if (0 == schema.compare(0,4,"scm:", 4))
	{
#ifdef HAVE_GUILE
		// Be friendly, and strip leading white-space, if any.
		size_t pos = 4;
		while (' ' == schema[pos]) pos++;

		SchemeEval* applier = SchemeEval::get_evaluator(as);
		Handle h(applier->apply(schema.substr(pos), args));

		// Exceptions were already caught, before leaving guile mode,
		// so we can't rethrow.  Just throw a new exception.
		if (applier->eval_error())
			throw RuntimeException(TRACE_INFO,
			    "Failed evaluation; see logfile for stack trace.");
		return h;
#else
		throw RuntimeException(TRACE_INFO,
		    "Cannot evaluate scheme GroundedSchemaNode!");
#endif /* HAVE_GUILE */
	}

	if (0 == schema.compare(0, 3,"py:", 3))
	{
#ifdef HAVE_CYTHON
		// Be friendly, and strip leading white-space, if any.
		size_t pos = 3;
		while (' ' == schema[pos]) pos++;

		// Get a reference to the python evaluator.
		// Be sure to specify the atomspace in which the
		// evaluation is to be performed.
		PythonEval &applier = PythonEval::instance();
		Handle h = applier.apply(as, schema.substr(pos), args);

		// Return the handle
		return h;
#else
		throw RuntimeException(TRACE_INFO,
		    "Cannot evaluate python GroundedSchemaNode!");
#endif /* HAVE_CYTHON */
	}

	if (0 == schema.compare(0,4,"lib:", 4))
	{
		// Be friendly, and strip leading white-space, if any.
		size_t pos = 4;
		while (' ' == schema[pos]) pos++;

		//Get the name of the Library and Function
		//They should be sperated by a .
		std::size_t dotpos = schema.find("\\");
		if (dotpos == std::string::npos)
		{
			throw RuntimeException(TRACE_INFO,
				"LibName and FunctionName not seperated by a '\\'");
		}
		std::string libName  = schema.substr(pos,dotpos-pos);
		std::string funcName = schema.substr(dotpos+1);

		void *libHandle;
		void * tmp;
		UUID (*func)(AtomSpace*, UUID);

		// Try and load the Library and the Function
		if ( (libHandle = dlopen(libName.c_str(), RTLD_LAZY)) == NULL ||
			 (tmp	   = dlsym(libHandle, funcName.c_str())) == NULL )
		{
			std::string err(dlerror());
			std::string msg = "Cannot Load function: " + funcName +" from lib: " + libName + " Error: " + err;
			throw RuntimeException(TRACE_INFO,
				msg.c_str());
		}

		// Convert the Void* pointer to the correct function Type
		func = reinterpret_cast<UUID (*)(AtomSpace *, UUID)>(tmp);

		// Execute the Function
		Handle h(func(as,args.value()));

		//Close Library after Use
		dlclose(libHandle);

		//Return the handle
		return h;
	}
	// Unkown proceedure type.
	throw RuntimeException(TRACE_INFO,
		"Cannot evaluate unknown GroundedSchemaNode!");
}
<|endoftext|>


<commit_before>#ifndef SRC_CONFIGURATION_H_
#define SRC_CONFIGURATION_H_

#include <horsewhisperer/horsewhisperer.h>

#include <boost/nowide/fstream.hpp>

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/member.hpp>

#include <memory>
#include <stdexcept>
#include <cstdint>

namespace PXPAgent {

//
// Tokens
//

extern const std::string DEFAULT_SPOOL_DIR;     // used by unit tests

//
// Types
//

using Types = HorseWhisperer::FlagType;

struct EntryBase
{
    // Config option name
    // HERE: must match one of the flag names and config file option
    std::string name;
    // CLI option aliases (e.g. --enable-transmogrification -t)
    std::string aliases;
    // Help string to be displayed by --help flag
    std::string help;
    // Value type
    Types type;
    // Whether the option was already parsed from config file
    bool configured = false;

    EntryBase(std::string _name, std::string _aliases, std::string _help, Types _type)
            : name { _name },
              aliases { _aliases },
              help { _help },
              type { _type } {
    }
};

template <typename T>
struct Entry : EntryBase
{
    // Default value
    T value;

    Entry<T>(std::string _name, std::string _aliases, std::string _help, Types _type,
             T _value)
            : EntryBase { _name, _aliases, _help, _type },
              value { _value } {
    }
};

using Base_ptr = std::unique_ptr<EntryBase>;

// Use a boost::multi_index container to allow accessing default
// options by key (option name) and insertion order
struct Option {
    std::string name;
    Base_ptr ptr;

    // boost::multi_index tag: retrieve option by name, map-style
    // NB: any type can be used as a multi-index tag
    struct ByName {};

    // boost::multi_index tag: retrieve option by insertion order,
    // vector-style
    struct ByInsertion {};
};

typedef boost::multi_index::multi_index_container<
    Option,
    boost::multi_index::indexed_by<
        boost::multi_index::hashed_unique<
            boost::multi_index::tag<Option::ByName>,
            boost::multi_index::member<Option,
                                       std::string,
                                       &Option::name>
        >,
        boost::multi_index::random_access<
            boost::multi_index::tag<Option::ByInsertion>
        >
    >
> Options;

//
// Platform-specific interface
//

/// Perform the platform specific configuration steps for setting up
/// the pxp-agent logging to file.
/// Throw a Configuration::Error in case of failure.
void configure_platform_file_logging();

//
// Configuration (singleton)
//

class Configuration
{
  public:
    struct Error : public std::runtime_error
    {
        explicit Error(std::string const& msg) : std::runtime_error(msg) {}
    };

    static Configuration& Instance()
    {
        static Configuration instance {};
        return instance;
    }

    struct Agent
    {
        std::string modules_dir;
        std::string broker_ws_uri;
        std::string failover_ws_uri;
        std::string ca;
        std::string crt;
        std::string key;
        std::string spool_dir;
        std::string spool_dir_purge_ttl;
        std::string modules_config_dir;
        std::string client_type;
        long ws_connection_timeout_ms;
        uint32_t association_timeout_s;
        uint32_t association_request_ttl_s;
        uint32_t pcp_message_ttl_s;
        uint32_t allowed_keepalive_timeouts;
    };

    /// Reset the HorseWhisperer singleton.
    /// Set the configuration entries to their default values and the
    /// specified start function that will be configured as the
    /// unique HorseWhisperer action for pxp-agent.
    /// Initialize the boost filesystem locale.
    void initialize(std::function<int(std::vector<std::string>)> start_function);

    /// Parse the command line arguments and, if specified, the
    /// configuration file.
    /// Return a HorseWhisperer::ParseResult value indicating the
    /// parsing outcome (refer to HorseWhisperer).
    /// Throw a HorseWhisperer::flag_validation_error in case such
    /// exception is thrown by a flag validation callback.
    /// Throw a Configuration::Error: if it fails to parse the CLI
    /// arguments; if the specified config file cannot be parsed or
    /// has any invalid JSON entry.
    HorseWhisperer::ParseResult parseOptions(int argc, char *argv[]);

    /// Validate logging configuration options and enable logging.
    /// Throw a Configuration::Error: in case of invalid the specified
    /// log file is in a non-esixtent directory.
    /// Other execeptions are propagated.
    void setupLogging();

    /// Ensure all required values are valid. If necessary, expand
    /// file paths to the expected format.
    /// Throw a Configuration::Error in case an option is set to an
    /// invalid value.
    void validate();

    /// If Configuration was already validated, return the value
    /// set for the specified flag (NB: the value can be a default);
    /// throw a Configuration::Error such flag is unknown.
    /// If Configuration was not validated so far, return the default
    /// value in case nd the requested flag is known or throw a
    /// Configuration::Error otherwise.
    template <typename T>
    T get(std::string flagname)
    {
        if (valid_) {
            try {
                return HorseWhisperer::GetFlag<T>(flagname);
            } catch (HorseWhisperer::undefined_flag_error& e) {
                throw Configuration::Error { std::string { e.what() } };
            }
        }

        const auto& opt_idx = getDefaultIndex(flagname);
        Entry<T>* entry_ptr = (Entry<T>*) opt_idx->ptr.get();
        return entry_ptr->value;
    }

    /// Set the specified value for a given configuration flag.
    /// Throw an Configuration::Error in case the Configuration was
    /// not initialized so far.
    /// Throw a Configuration::Error in case the specified flag is
    /// unknown or the value is invalid.
    template<typename T>
    void set(std::string flagname, T value)
    {
        checkValidForSetting();

        try {
            HorseWhisperer::SetFlag<T>(flagname, value);
        } catch (HorseWhisperer::flag_validation_error) {
            throw Configuration::Error { getInvalidFlagError(flagname) };
        } catch (HorseWhisperer::undefined_flag_error) {
            throw Configuration::Error { getUnknownFlagError(flagname) };
        }
    }

    /// Return an object containing all agent configuration options
    const Agent& getAgentConfiguration() const;

    /// Try to close the log file stream,  then try to open the log
    /// file in append mode and associate it to the log file stream.
    /// All possible exceptions will be filtered.
    void reopenLogfile() const;

  private:
    // Whether the Configuration singleton has successfully validated
    // all options specified by both CLI and file
    bool valid_;

    // Stores options with relative default values
    Options defaults_;

    // Path to the pxp-agent configuration file
    std::string config_file_;

    // Function that starts the pxp-agent service
    std::function<int(std::vector<std::string>)> start_function_;

    // Cache for agent configuration parameters
    mutable Agent agent_configuration_;

    // Path to the logfile
    std::string logfile_;

    // Stream abstraction object for the logfile
    mutable boost::nowide::ofstream logfile_fstream_;

    // Defines the default values
    Configuration();

    void defineDefaultValues();
    void setDefaultValues();
    void setStartAction();
    void parseConfigFile();
    void validateAndNormalizeWebsocketSettings();
    void validateAndNormalizeOtherSettings();
    void setAgentConfiguration();
    const Options::iterator getDefaultIndex(const std::string& flagname);
    std::string getInvalidFlagError(const std::string& flagname);
    std::string getUnknownFlagError(const std::string& flagname);
    void checkValidForSetting();
};

}  // namespace PXPAgent

#endif  // SRC_CONFIGURATION_H_
<commit_msg>(maint) Use move semantics<commit_after>#ifndef SRC_CONFIGURATION_H_
#define SRC_CONFIGURATION_H_

#include <horsewhisperer/horsewhisperer.h>

#include <boost/nowide/fstream.hpp>

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/member.hpp>

#include <memory>
#include <stdexcept>
#include <cstdint>

namespace PXPAgent {

//
// Tokens
//

extern const std::string DEFAULT_SPOOL_DIR;     // used by unit tests

//
// Types
//

using Types = HorseWhisperer::FlagType;

struct EntryBase
{
    // Config option name
    // HERE: must match one of the flag names and config file option
    std::string name;
    // CLI option aliases (e.g. --enable-transmogrification -t)
    std::string aliases;
    // Help string to be displayed by --help flag
    std::string help;
    // Value type
    Types type;
    // Whether the option was already parsed from config file
    bool configured = false;

    EntryBase(std::string _name, std::string _aliases, std::string _help, Types _type)
            : name { std::move(_name) },
              aliases { std::move(_aliases) },
              help { std::move(_help) },
              type { std::move(_type) } {
    }
};

template <typename T>
struct Entry : EntryBase
{
    // Default value
    T value;

    Entry<T>(std::string _name, std::string _aliases, std::string _help, Types _type,
             T _value)
            : EntryBase { std::move(_name), std::move(_aliases), std::move(_help), std::move(_type) },
              value { std::move(_value) } {
    }
};

using Base_ptr = std::unique_ptr<EntryBase>;

// Use a boost::multi_index container to allow accessing default
// options by key (option name) and insertion order
struct Option {
    std::string name;
    Base_ptr ptr;

    // boost::multi_index tag: retrieve option by name, map-style
    // NB: any type can be used as a multi-index tag
    struct ByName {};

    // boost::multi_index tag: retrieve option by insertion order,
    // vector-style
    struct ByInsertion {};
};

typedef boost::multi_index::multi_index_container<
    Option,
    boost::multi_index::indexed_by<
        boost::multi_index::hashed_unique<
            boost::multi_index::tag<Option::ByName>,
            boost::multi_index::member<Option,
                                       std::string,
                                       &Option::name>
        >,
        boost::multi_index::random_access<
            boost::multi_index::tag<Option::ByInsertion>
        >
    >
> Options;

//
// Platform-specific interface
//

/// Perform the platform specific configuration steps for setting up
/// the pxp-agent logging to file.
/// Throw a Configuration::Error in case of failure.
void configure_platform_file_logging();

//
// Configuration (singleton)
//

class Configuration
{
  public:
    struct Error : public std::runtime_error
    {
        explicit Error(std::string const& msg) : std::runtime_error(msg) {}
    };

    static Configuration& Instance()
    {
        static Configuration instance {};
        return instance;
    }

    struct Agent
    {
        std::string modules_dir;
        std::string broker_ws_uri;
        std::string failover_ws_uri;
        std::string ca;
        std::string crt;
        std::string key;
        std::string spool_dir;
        std::string spool_dir_purge_ttl;
        std::string modules_config_dir;
        std::string client_type;
        long ws_connection_timeout_ms;
        uint32_t association_timeout_s;
        uint32_t association_request_ttl_s;
        uint32_t pcp_message_ttl_s;
        uint32_t allowed_keepalive_timeouts;
    };

    /// Reset the HorseWhisperer singleton.
    /// Set the configuration entries to their default values and the
    /// specified start function that will be configured as the
    /// unique HorseWhisperer action for pxp-agent.
    /// Initialize the boost filesystem locale.
    void initialize(std::function<int(std::vector<std::string>)> start_function);

    /// Parse the command line arguments and, if specified, the
    /// configuration file.
    /// Return a HorseWhisperer::ParseResult value indicating the
    /// parsing outcome (refer to HorseWhisperer).
    /// Throw a HorseWhisperer::flag_validation_error in case such
    /// exception is thrown by a flag validation callback.
    /// Throw a Configuration::Error: if it fails to parse the CLI
    /// arguments; if the specified config file cannot be parsed or
    /// has any invalid JSON entry.
    HorseWhisperer::ParseResult parseOptions(int argc, char *argv[]);

    /// Validate logging configuration options and enable logging.
    /// Throw a Configuration::Error: in case of invalid the specified
    /// log file is in a non-esixtent directory.
    /// Other execeptions are propagated.
    void setupLogging();

    /// Ensure all required values are valid. If necessary, expand
    /// file paths to the expected format.
    /// Throw a Configuration::Error in case an option is set to an
    /// invalid value.
    void validate();

    /// If Configuration was already validated, return the value
    /// set for the specified flag (NB: the value can be a default);
    /// throw a Configuration::Error such flag is unknown.
    /// If Configuration was not validated so far, return the default
    /// value in case nd the requested flag is known or throw a
    /// Configuration::Error otherwise.
    template <typename T>
    T get(std::string flagname)
    {
        if (valid_) {
            try {
                return HorseWhisperer::GetFlag<T>(flagname);
            } catch (HorseWhisperer::undefined_flag_error& e) {
                throw Configuration::Error { std::string { e.what() } };
            }
        }

        const auto& opt_idx = getDefaultIndex(flagname);
        Entry<T>* entry_ptr = (Entry<T>*) opt_idx->ptr.get();
        return entry_ptr->value;
    }

    /// Set the specified value for a given configuration flag.
    /// Throw an Configuration::Error in case the Configuration was
    /// not initialized so far.
    /// Throw a Configuration::Error in case the specified flag is
    /// unknown or the value is invalid.
    template<typename T>
    void set(std::string flagname, T value)
    {
        checkValidForSetting();

        try {
            HorseWhisperer::SetFlag<T>(flagname, value);
        } catch (HorseWhisperer::flag_validation_error) {
            throw Configuration::Error { getInvalidFlagError(flagname) };
        } catch (HorseWhisperer::undefined_flag_error) {
            throw Configuration::Error { getUnknownFlagError(flagname) };
        }
    }

    /// Return an object containing all agent configuration options
    const Agent& getAgentConfiguration() const;

    /// Try to close the log file stream,  then try to open the log
    /// file in append mode and associate it to the log file stream.
    /// All possible exceptions will be filtered.
    void reopenLogfile() const;

  private:
    // Whether the Configuration singleton has successfully validated
    // all options specified by both CLI and file
    bool valid_;

    // Stores options with relative default values
    Options defaults_;

    // Path to the pxp-agent configuration file
    std::string config_file_;

    // Function that starts the pxp-agent service
    std::function<int(std::vector<std::string>)> start_function_;

    // Cache for agent configuration parameters
    mutable Agent agent_configuration_;

    // Path to the logfile
    std::string logfile_;

    // Stream abstraction object for the logfile
    mutable boost::nowide::ofstream logfile_fstream_;

    // Defines the default values
    Configuration();

    void defineDefaultValues();
    void setDefaultValues();
    void setStartAction();
    void parseConfigFile();
    void validateAndNormalizeWebsocketSettings();
    void validateAndNormalizeOtherSettings();
    void setAgentConfiguration();
    const Options::iterator getDefaultIndex(const std::string& flagname);
    std::string getInvalidFlagError(const std::string& flagname);
    std::string getUnknownFlagError(const std::string& flagname);
    void checkValidForSetting();
};

}  // namespace PXPAgent

#endif  // SRC_CONFIGURATION_H_
<|endoftext|>