peerapi/src/peerapi.cc

324 lines
7.4 KiB
C++

/*
* Copyright 2016 The PeerApi Project Authors. All rights reserved.
*
* Ryan Lee
*/
#include <string>
#include <locale>
#include "peerapi.h"
#include "control.h"
#include "logging.h"
namespace peerapi {
Peer::Peer( const string peer_id ) {
// Log level
#if DEBUG || _DEBUG
rtc::LogMessage::LogToDebug( rtc::LS_NONE );
peerapi::LogMessage::LogToDebug( peerapi::WARNING );
#else
rtc::LogMessage::LogToDebug( rtc::LS_NONE );
peerapi::LogMessage::LogToDebug( peerapi::LS_NONE );
#endif
string local_peer_id;
if ( peer_id.empty() ) {
local_peer_id = rtc::CreateRandomUuid();
}
else {
local_peer_id = peer_id;
}
peer_id_ = local_peer_id;
close_once_ = false;
LOG_F( INFO ) << "Done";
}
Peer::~Peer() {
LOG_F( INFO ) << "Done";
}
void Peer::Run() {
rtc::ThreadManager::Instance()->CurrentThread()->Run();
LOG_F( INFO ) << "Done";
}
void Peer::Stop() {
rtc::ThreadManager::Instance()->CurrentThread()->Quit();
LOG_F( INFO ) << "Done";
}
void Peer::Open() {
if ( control_.get() != nullptr ) {
LOG_F( WARNING ) << "Already open.";
return;
}
//
// create signal client
//
if ( signal_ == nullptr ) {
signal_ = std::make_shared<peerapi::Signal>( setting_.signal_uri_ );
}
//
// Initialize control
//
control_ = std::make_shared<peerapi::Control>( signal_ );
control_->RegisterObserver( this, control_ );
if ( control_.get() == NULL ) {
LOG_F( LERROR ) << "Failed to create class Control.";
return;
}
//
// Initialize peer connection
//
if ( !control_->InitializeControl() ) {
LOG_F( LERROR ) << "Failed to initialize Control.";
control_.reset();
return;
}
//
// Connect to signal server
//
control_->Open( setting_.signal_id_, setting_.signal_password_, peer_id_ );
LOG_F( INFO ) << "Done";
return;
}
void Peer::Close( const string peer_id ) {
if ( peer_id.empty() || peer_id == peer_id_ ) {
control_->Close( CLOSE_NORMAL, FORCE_QUEUING_ON );
signal_->SyncClose();
}
else {
control_->ClosePeer( peer_id, CLOSE_NORMAL, FORCE_QUEUING_ON );
}
LOG_F( INFO ) << "Done";
}
void Peer::Connect( const string peer_id ) {
control_->Connect( peer_id );
LOG_F( INFO ) << "Done, peer is " << peer_id;
return;
}
//
// Send message to destination peer session id
//
bool Peer::Send( const string& peer_id, const char* data, const size_t size, const bool wait ) {
if ( wait ) {
//
// Synchronous send returns true or false
// and a timeout is 60*1000 ms by default.
//
return control_->SyncSend( peer_id, data, size );
}
else {
control_->Send( peer_id, data, size );
//
// Asyncronous send always returns true and
// trigger 'close' event with CloseCode if failed
//
return true;
}
}
bool Peer::Send( const string& peer_id, const string& message, const bool wait ) {
return Send( peer_id, message.c_str(), message.size(), wait );
}
bool Peer::SetOptions( const string options ) {
// parse settings
if ( !options.empty() ) {
return ParseOptions( options );
}
return true;
}
std::string Peer::CreateRandomUuid() {
return rtc::CreateRandomUuid();
}
//
// Register Event handler
//
Peer& Peer::On( string event_id, std::function<void( string )> handler ) {
if ( event_id.empty() ) return *this;
if ( event_id == "open" || event_id == "connect" || event_id == "writable" ) {
std::unique_ptr<EventHandler_2> f( new EventHandler_2( handler ) );
event_handler_.insert( Events::value_type( event_id, std::move( f ) ) );
LOG_F( INFO ) << "An event handler '" << event_id << "' has been inserted";
}
else {
LOG_F( LERROR ) << "Unsupported event type: " << event_id;
}
return *this;
}
Peer& Peer::On( string event_id, std::function<void( string, string )> handler ) {
if ( event_id.empty() ) return *this;
LOG_F( LERROR ) << "Unsupported event type: " << event_id;
return *this;
}
Peer& Peer::On( string event_id, std::function<void( string, peerapi::CloseCode, string )> handler ) {
if ( event_id.empty() ) return *this;
if ( event_id == "close" ) {
std::unique_ptr<EventHandler_Close> f( new EventHandler_Close( handler ) );
event_handler_.insert( Events::value_type( event_id, std::move( f ) ) );
LOG_F( INFO ) << "An event handler '" << event_id << "' has been inserted";
}
else {
LOG_F( LERROR ) << "Unsupported event type: " << event_id;
}
return *this;
}
Peer& Peer::On( string event_id, std::function<void( string, char*, std::size_t )> handler ) {
if ( event_id.empty() ) return *this;
if ( event_id == "message" ) {
std::unique_ptr<EventHandler_Message> f( new EventHandler_Message( handler ) );
event_handler_.insert( Events::value_type( event_id, std::move( f ) ) );
LOG_F( INFO ) << "An event handler '" << event_id << "' has been inserted";
}
else {
LOG_F( LERROR ) << "Unsupported event type: " << event_id;
}
return *this;
}
//
// Signal event handler
//
void Peer::OnOpen( const string peer_id ) {
close_once_ = false;
if ( event_handler_.find( "open" ) != event_handler_.end() ) {
CallEventHandler( "open", peer_id );
}
LOG_F( INFO ) << "Done";
}
void Peer::OnClose( const string peer_id, const CloseCode code, const string desc ) {
// This instance of Peer and local peer is going to be closed
if ( peer_id == peer_id_ ) {
if ( close_once_ ) {
LOG_F( WARNING ) << "close_ is false, peer is " << peer_id;
return;
}
close_once_ = true;
if ( event_handler_.find( "close" ) != event_handler_.end() ) {
CallEventHandler( "close", peer_id, code, desc );
}
control_->UnregisterObserver();
control_.reset();
}
// Remote peer has been closed
else {
if ( event_handler_.find( "close" ) != event_handler_.end() ) {
CallEventHandler( "close", peer_id, code, desc );
}
}
LOG_F( INFO ) << "Done, peer is " << peer_id;
}
void Peer::OnConnect( const string peer_id ) {
if ( event_handler_.find( "connect" ) != event_handler_.end() ) {
CallEventHandler( "connect", peer_id );
}
LOG_F( INFO ) << "Done, peer is " << peer_id;
}
void Peer::OnMessage( const string peer_id, const char* data, const size_t size ) {
if ( event_handler_.find( "message" ) != event_handler_.end() ) {
CallEventHandler( "message", peer_id, data, size );
}
}
void Peer::OnWritable( const string peer_id ) {
if ( event_handler_.find( "writable" ) != event_handler_.end() ) {
CallEventHandler( "writable", peer_id );
}
LOG_F( INFO ) << "Done, peer is " << peer_id;
}
template<typename ...A>
void Peer::CallEventHandler( string msg_id, A&& ... args )
{
using eventhandler_t = EventHandler_t<A...>;
using cb_t = std::function<void( A... )>;
const Handler_t& base = *event_handler_[msg_id];
const cb_t& func = static_cast<const eventhandler_t&>( base ).callback_;
func( std::forward<A>( args )... );
}
bool Peer::ParseOptions( const string& options ) {
Json::Reader reader;
Json::Value joptions;
string value;
if ( !reader.parse( options, joptions ) ) {
LOG_F( WARNING ) << "Invalid setting: " << options;
return false;
}
if ( rtc::GetStringFromJsonObject( joptions, "url", &value ) ) {
setting_.signal_uri_ = value;
}
if ( rtc::GetStringFromJsonObject( joptions, "user_id", &value ) ) {
setting_.signal_id_ = value;
}
if ( rtc::GetStringFromJsonObject( joptions, "user_password", &value ) ) {
setting_.signal_password_ = value;
}
return true;
}
} // namespace peerapi