Files
GacUI/Import/VlppWorkflowLibrary.cpp
T
2026-06-18 02:21:28 -07:00

5906 lines
196 KiB
C++

/***********************************************************************
THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY
DEVELOPER: Zihan Chen(vczh)
***********************************************************************/
#include "VlppWorkflowLibrary.h"
/***********************************************************************
.\WFLIBRARYCPPHELPER.CPP
***********************************************************************/
namespace vl
{
namespace __vwsn
{
/***********************************************************************
CreateArray
***********************************************************************/
CreateArray::CreateArray()
:list(IValueArray::Create())
{
}
CreateArray::CreateArray(Ptr<IValueArray> _list)
:list(_list)
{
}
/***********************************************************************
CreateList
***********************************************************************/
CreateList::CreateList()
:list(IValueList::Create())
{
}
CreateList::CreateList(Ptr<IValueList> _list)
:list(_list)
{
}
/***********************************************************************
CreateObservableList
***********************************************************************/
CreateObservableList::CreateObservableList()
:list(IValueObservableList::Create())
{
}
CreateObservableList::CreateObservableList(Ptr<IValueObservableList> _list)
:list(_list)
{
}
/***********************************************************************
CreateDictionary
***********************************************************************/
CreateDictionary::CreateDictionary()
:dictionary(IValueDictionary::Create())
{
}
CreateDictionary::CreateDictionary(Ptr<IValueDictionary> _dictionary)
:dictionary(_dictionary)
{
}
}
}
/***********************************************************************
.\WFLIBRARYPREDEFINED.CPP
***********************************************************************/
namespace vl
{
using namespace collections;
namespace reflection
{
namespace description
{
/***********************************************************************
CoroutineResult
***********************************************************************/
Value CoroutineResult::GetResult()
{
return result;
}
void CoroutineResult::SetResult(const Value& value)
{
result = value;
}
Ptr<IValueException> CoroutineResult::GetFailure()
{
return failure;
}
void CoroutineResult::SetFailure(Ptr<IValueException> value)
{
failure = value;
}
/***********************************************************************
EnumerableCoroutine
***********************************************************************/
class CoroutineEnumerator : public Object, public virtual EnumerableCoroutine::IImpl, public Description<CoroutineEnumerator>
{
protected:
EnumerableCoroutine::Creator creator;
Ptr<ICoroutine> coroutine;
Value current;
vint index = -1;
Ptr<IValueEnumerator> joining;
public:
CoroutineEnumerator(const EnumerableCoroutine::Creator& _creator)
:creator(_creator)
{
}
Value GetCurrent()override
{
return current;
}
vint GetIndex()override
{
return index;
}
bool Next()override
{
if (!coroutine)
{
coroutine = creator(this);
}
while (coroutine->GetStatus() == CoroutineStatus::Waiting)
{
if (joining)
{
if (joining->Next())
{
current = joining->GetCurrent();
index++;
return true;
}
else
{
joining = nullptr;
}
}
coroutine->Resume(true, nullptr);
if (coroutine->GetStatus() != CoroutineStatus::Waiting)
{
break;
}
if (!joining)
{
index++;
return true;
}
}
return false;
}
void OnYield(const Value& value)override
{
current = value;
joining = nullptr;
}
void OnJoin(Ptr<IValueEnumerable> value)override
{
if (!value)
{
throw Exception(L"Cannot join a null collection.");
}
current = Value();
joining = value->CreateEnumerator();
}
};
class CoroutineEnumerable : public Object, public virtual IValueEnumerable, public Description<CoroutineEnumerable>
{
protected:
EnumerableCoroutine::Creator creator;
public:
CoroutineEnumerable(const EnumerableCoroutine::Creator& _creator)
:creator(_creator)
{
}
Ptr<IValueEnumerator> CreateEnumerator()override
{
return Ptr(new CoroutineEnumerator(creator));
}
};
void EnumerableCoroutine::YieldAndPause(IImpl* impl, const Value& value)
{
impl->OnYield(value);
}
void EnumerableCoroutine::JoinAndPause(IImpl* impl, Ptr<IValueEnumerable> value)
{
impl->OnJoin(value);
}
void EnumerableCoroutine::ReturnAndExit(IImpl* impl)
{
}
Ptr<IValueEnumerable> EnumerableCoroutine::Create(const Creator& creator)
{
return Ptr(new CoroutineEnumerable(creator));
}
/***********************************************************************
AsyncContext
***********************************************************************/
AsyncContext::AsyncContext(const Value& _context)
:context(_context)
{
}
AsyncContext::~AsyncContext()
{
}
bool AsyncContext::IsCancelled()
{
SPIN_LOCK(lock)
{
return cancelled;
}
CHECK_FAIL(L"Not reachable");
}
bool AsyncContext::Cancel()
{
SPIN_LOCK(lock)
{
if (cancelled) return false;
cancelled = true;
return true;
}
CHECK_FAIL(L"Not reachable");
}
const description::Value& AsyncContext::GetContext()
{
SPIN_LOCK(lock)
{
return context;
}
CHECK_FAIL(L"Not reachable");
}
void AsyncContext::SetContext(const description::Value& value)
{
SPIN_LOCK(lock)
{
context = value;
}
}
/***********************************************************************
DelayAsync
***********************************************************************/
class DelayAsync : public Object, public virtual IAsync, public Description<DelayAsync>
{
protected:
SpinLock lock;
vint milliseconds;
AsyncStatus status = AsyncStatus::Ready;
public:
DelayAsync(vint _milliseconds)
:milliseconds(_milliseconds)
{
}
AsyncStatus GetStatus()override
{
return status;
}
bool Execute(const Func<void(Ptr<CoroutineResult>)>& _callback, Ptr<AsyncContext> context)override
{
SPIN_LOCK(lock)
{
if (status != AsyncStatus::Ready) return false;
status = AsyncStatus::Executing;
IAsyncScheduler::GetSchedulerForCurrentThread()->DelayExecute([async = Ptr<DelayAsync>(this), callback = _callback]()
{
if (callback)
{
callback(nullptr);
}
}, milliseconds);
}
return true;
}
};
Ptr<IAsync> IAsync::Delay(vint milliseconds)
{
return Ptr(new DelayAsync(milliseconds));
}
/***********************************************************************
FutureAndPromiseAsync
***********************************************************************/
class FutureAndPromiseAsync : public virtual IFuture, public virtual IPromise, public Description<FutureAndPromiseAsync>
{
public:
SpinLock lock;
AsyncStatus status = AsyncStatus::Ready;
Ptr<CoroutineResult> cr;
Func<void(Ptr<CoroutineResult>)> callback;
void ExecuteCallbackAndClear()
{
status = AsyncStatus::Stopped;
if (callback)
{
callback(cr);
}
cr = nullptr;
callback = {};
}
template<typename F>
bool Send(F f)
{
SPIN_LOCK(lock)
{
if (status == AsyncStatus::Stopped || cr) return false;
cr = Ptr(new CoroutineResult);
f();
if (status == AsyncStatus::Executing)
{
ExecuteCallbackAndClear();
}
}
return true;
}
AsyncStatus GetStatus()override
{
return status;
}
bool Execute(const Func<void(Ptr<CoroutineResult>)>& _callback, Ptr<AsyncContext> context)override
{
SPIN_LOCK(lock)
{
if (status != AsyncStatus::Ready) return false;
callback = _callback;
if (cr)
{
ExecuteCallbackAndClear();
}
else
{
status = AsyncStatus::Executing;
}
}
return true;
}
Ptr<IPromise> GetPromise()override
{
return Ptr(this);
}
bool SendResult(const Value& result)override
{
return Send([=, this]()
{
cr->SetResult(result);
});
}
bool SendFailure(Ptr<IValueException> failure)override
{
return Send([=, this]()
{
cr->SetFailure(failure);
});
}
};
Ptr<IFuture> IFuture::Create()
{
return Ptr(new FutureAndPromiseAsync);
}
/***********************************************************************
IAsyncScheduler
***********************************************************************/
class AsyncSchedulerMap
{
public:
Dictionary<vint, Ptr<IAsyncScheduler>> schedulers;
Ptr<IAsyncScheduler> defaultScheduler;
};
AsyncSchedulerMap* asyncSchedulerMap = nullptr;
SpinLock asyncSchedulerLock;
#define ENSURE_ASYNC_SCHEDULER_MAP\
if (!asyncSchedulerMap) asyncSchedulerMap = new AsyncSchedulerMap;
#define DISPOSE_ASYNC_SCHEDULER_MAP_IF_NECESSARY\
if (asyncSchedulerMap->schedulers.Count() == 0 && !asyncSchedulerMap->defaultScheduler)\
{\
delete asyncSchedulerMap;\
asyncSchedulerMap = nullptr;\
}\
void IAsyncScheduler::RegisterDefaultScheduler(Ptr<IAsyncScheduler> scheduler)
{
SPIN_LOCK(asyncSchedulerLock)
{
ENSURE_ASYNC_SCHEDULER_MAP
CHECK_ERROR(!asyncSchedulerMap->defaultScheduler, L"IAsyncScheduler::RegisterDefaultScheduler()#A default scheduler has already been registered.");
asyncSchedulerMap->defaultScheduler = scheduler;
}
}
void IAsyncScheduler::RegisterSchedulerForCurrentThread(Ptr<IAsyncScheduler> scheduler)
{
SPIN_LOCK(asyncSchedulerLock)
{
ENSURE_ASYNC_SCHEDULER_MAP
CHECK_ERROR(!asyncSchedulerMap->schedulers.Keys().Contains(Thread::GetCurrentThreadId()), L"IAsyncScheduler::RegisterDefaultScheduler()#A scheduler for this thread has already been registered.");
asyncSchedulerMap->schedulers.Add(Thread::GetCurrentThreadId(), scheduler);
}
}
Ptr<IAsyncScheduler> IAsyncScheduler::UnregisterDefaultScheduler()
{
Ptr<IAsyncScheduler> scheduler;
SPIN_LOCK(asyncSchedulerLock)
{
if (asyncSchedulerMap)
{
scheduler = asyncSchedulerMap->defaultScheduler;
asyncSchedulerMap->defaultScheduler = nullptr;
DISPOSE_ASYNC_SCHEDULER_MAP_IF_NECESSARY
}
}
return scheduler;
}
Ptr<IAsyncScheduler> IAsyncScheduler::UnregisterSchedulerForCurrentThread()
{
Ptr<IAsyncScheduler> scheduler;
SPIN_LOCK(asyncSchedulerLock)
{
if (asyncSchedulerMap)
{
vint index = asyncSchedulerMap->schedulers.Keys().IndexOf(Thread::GetCurrentThreadId());
if (index != -1)
{
scheduler = asyncSchedulerMap->schedulers.Values()[index];
asyncSchedulerMap->schedulers.Remove(Thread::GetCurrentThreadId());
}
DISPOSE_ASYNC_SCHEDULER_MAP_IF_NECESSARY
}
}
return scheduler;
}
#undef ENSURE_ASYNC_SCHEDULER_MAP
#undef DISPOSE_ASYNC_SCHEDULER_MAP_IF_NECESSARY
Ptr<IAsyncScheduler> IAsyncScheduler::GetSchedulerForCurrentThread()
{
Ptr<IAsyncScheduler> scheduler;
SPIN_LOCK(asyncSchedulerLock)
{
CHECK_ERROR(asyncSchedulerMap != nullptr, L"IAsyncScheduler::GetSchedulerForCurrentThread()#There is no scheduler registered for the current thread.");
vint index = asyncSchedulerMap->schedulers.Keys().IndexOf(Thread::GetCurrentThreadId());
if (index != -1)
{
scheduler = asyncSchedulerMap->schedulers.Values()[index];
}
else if (asyncSchedulerMap->defaultScheduler)
{
scheduler = asyncSchedulerMap->defaultScheduler;
}
else
{
CHECK_FAIL(L"IAsyncScheduler::GetSchedulerForCurrentThread()#There is no scheduler registered for the current thread.");
}
}
return scheduler;
}
/***********************************************************************
AsyncCoroutine
***********************************************************************/
class CoroutineAsync : public Object, public virtual AsyncCoroutine::IImpl, public Description<CoroutineAsync>
{
protected:
Ptr<ICoroutine> coroutine;
AsyncCoroutine::Creator creator;
Ptr<IAsyncScheduler> scheduler;
Func<void(Ptr<CoroutineResult>)> callback;
Ptr<AsyncContext> context;
Value result;
public:
CoroutineAsync(AsyncCoroutine::Creator _creator)
:creator(_creator)
{
}
AsyncStatus GetStatus()override
{
if (!coroutine)
{
return AsyncStatus::Ready;
}
else if (coroutine->GetStatus() != CoroutineStatus::Stopped)
{
return AsyncStatus::Executing;
}
else
{
return AsyncStatus::Stopped;
}
}
bool Execute(const Func<void(Ptr<CoroutineResult>)>& _callback, Ptr<AsyncContext> _context)override
{
if (coroutine) return false;
scheduler = IAsyncScheduler::GetSchedulerForCurrentThread();
callback = _callback;
context = _context;
coroutine = creator(this);
OnContinue(nullptr);
return true;
}
Ptr<IAsyncScheduler> GetScheduler()override
{
return scheduler;
}
Ptr<AsyncContext> GetContext()override
{
if (!context)
{
context = Ptr(new AsyncContext);
}
return context;
}
void OnContinue(Ptr<CoroutineResult> output)override
{
scheduler->Execute([async = Ptr<CoroutineAsync>(this), output]()
{
async->coroutine->Resume(false, output);
if (async->coroutine->GetStatus() == CoroutineStatus::Stopped && async->callback)
{
auto result = Ptr(new CoroutineResult);
if (async->coroutine->GetFailure())
{
result->SetFailure(async->coroutine->GetFailure());
}
else
{
result->SetResult(async->result);
}
async->callback(result);
}
});
}
void OnReturn(const Value& value)override
{
result = value;
}
};
void AsyncCoroutine::AwaitAndRead(IImpl* impl, Ptr<IAsync> value)
{
value->Execute([async = Ptr<IImpl>(impl)](auto output)
{
async->OnContinue(output);
}, impl->GetContext());
}
void AsyncCoroutine::ReturnAndExit(IImpl* impl, const Value& value)
{
impl->OnReturn(value);
}
Ptr<AsyncContext> AsyncCoroutine::QueryContext(IImpl* impl)
{
return impl->GetContext();
}
Ptr<IAsync> AsyncCoroutine::Create(const Creator& creator)
{
return Ptr(new CoroutineAsync(creator));
}
void AsyncCoroutine::CreateAndRun(const Creator& creator)
{
Ptr(new CoroutineAsync(creator))->Execute(
[](Ptr<CoroutineResult> cr)
{
if (cr->GetFailure())
{
#pragma push_macro("GetMessage")
#if defined GetMessage
#undef GetMessage
#endif
throw Exception(cr->GetFailure()->GetMessage());
#pragma pop_macro("GetMessage")
}
}, nullptr);
}
/***********************************************************************
StateMachine
***********************************************************************/
void StateMachine::ResumeStateMachine()
{
Ptr<CoroutineResult> previousResult;
while (true)
{
if (stateMachineCoroutine == nullptr)
{
if (!stateMachineInitialized)
{
throw Exception(L"The state machine has not been initialized.");
}
if (stateMachineStopped)
{
throw Exception(L"The state machine has been stopped.");
}
stateMachineStopped = true;
if (previousResult)
{
if (auto failure = previousResult->GetFailure())
{
throw Exception(failure->GetMessage());
}
}
break;
}
else if (stateMachineCoroutine->GetStatus() != CoroutineStatus::Stopped)
{
auto currentCoroutine = stateMachineCoroutine;
currentCoroutine->Resume(false, previousResult);
if (stateMachineCoroutine == currentCoroutine)
{
// wait for input
break;
}
else if (currentCoroutine->GetStatus() == CoroutineStatus::Stopped)
{
// leave a state machine
previousResult = Ptr(new CoroutineResult);
if (auto failure = currentCoroutine->GetFailure())
{
previousResult->SetFailure(failure);
}
}
else
{
// enter a state machine
}
}
}
}
StateMachine::StateMachine()
{
}
StateMachine::~StateMachine()
{
FinalizeAggregation();
}
CoroutineStatus StateMachine::GetStateMachineStatus()
{
if (stateMachineStopped)
{
return CoroutineStatus::Stopped;
}
else if (stateMachineCoroutine)
{
if (stateMachineCoroutine->GetStatus() == CoroutineStatus::Waiting)
{
return CoroutineStatus::Waiting;
}
else
{
return CoroutineStatus::Executing;
}
}
else
{
return CoroutineStatus::Waiting;
}
}
/***********************************************************************
Sys
***********************************************************************/
namespace system_sys
{
class ReverseEnumerable : public Object, public IValueEnumerable
{
protected:
Ptr<IValueReadonlyList> list;
class Enumerator : public Object, public IValueEnumerator
{
protected:
Ptr<IValueReadonlyList> list;
vint index;
public:
Enumerator(Ptr<IValueReadonlyList> _list)
:list(_list), index(_list->GetCount())
{
}
Value GetCurrent()
{
return list->Get(index);
}
vint GetIndex()
{
return list->GetCount() - 1 - index;
}
bool Next()
{
if (index <= 0) return false;
index--;
return true;
}
};
public:
ReverseEnumerable(Ptr<IValueReadonlyList> _list)
:list(_list)
{
}
Ptr<IValueEnumerator> CreateEnumerator()override
{
return Ptr(new Enumerator(list));
}
};
}
DateTime Sys::GetLocalTime()
{
return DateTime::LocalTime();
}
DateTime Sys::GetUtcTime()
{
return DateTime::UtcTime();
}
DateTime Sys::ToLocalTime(DateTime dt)
{
return dt.ToLocalTime();
}
DateTime Sys::ToUtcTime(DateTime dt)
{
return dt.ToUtcTime();
}
DateTime Sys::Forward(DateTime dt, vuint64_t milliseconds)
{
return dt.Forward(milliseconds);
}
DateTime Sys::Backward(DateTime dt, vuint64_t milliseconds)
{
return dt.Backward(milliseconds);
}
DateTime Sys::CreateDateTime(vint year, vint month, vint day)
{
return DateTime::FromDateTime(year, month, day);
}
DateTime Sys::CreateDateTime(vint year, vint month, vint day, vint hour, vint minute, vint second, vint milliseconds)
{
return DateTime::FromDateTime(year, month, day, hour, minute, second, milliseconds);
}
Ptr<IValueEnumerable> Sys::ReverseEnumerable(Ptr<IValueEnumerable> value)
{
auto list = value.Cast<IValueReadonlyList>();
if (!list)
{
list = IValueList::Create(GetLazyList<Value>(value));
}
return Ptr(new system_sys::ReverseEnumerable(list));
}
#define DEFINE_COMPARE(TYPE)\
vint Sys::Compare(TYPE a, TYPE b)\
{\
auto result = a <=> b;\
if (result < 0) return -1;\
if (result > 0) return 1;\
return 0;\
}\
REFLECTION_PREDEFINED_PRIMITIVE_TYPES(DEFINE_COMPARE)
DEFINE_COMPARE(DateTime)
#undef DEFINE_COMPARE
/***********************************************************************
Math
***********************************************************************/
#define DEFINE_MINMAX(TYPE)\
TYPE Math::Min(TYPE a, TYPE b)\
{\
return Sys::Compare(a, b) < 0 ? a : b;\
}\
TYPE Math::Max(TYPE a, TYPE b)\
{\
return Sys::Compare(a, b) > 0 ? a : b;\
}\
REFLECTION_PREDEFINED_PRIMITIVE_TYPES(DEFINE_MINMAX)
DEFINE_MINMAX(DateTime)
#undef DEFINE_MINMAX
/***********************************************************************
Localization
***********************************************************************/
Locale Localization::Invariant()
{
return Locale::Invariant();
}
Locale Localization::System()
{
return Locale::SystemDefault();
}
Locale Localization::User()
{
return Locale::UserDefault();
}
collections::LazyList<Locale> Localization::Locales()
{
auto result = Ptr(new List<Locale>);
Locale::Enumerate(*result.Obj());
return result;
}
collections::LazyList<WString> Localization::GetShortDateFormats(Locale locale)
{
auto result = Ptr(new List<WString>);
locale.GetShortDateFormats(*result.Obj());
return result;
}
collections::LazyList<WString> Localization::GetLongDateFormats(Locale locale)
{
auto result = Ptr(new List<WString>);
locale.GetLongDateFormats(*result.Obj());
return result;
}
collections::LazyList<WString> Localization::GetYearMonthDateFormats(Locale locale)
{
auto result = Ptr(new List<WString>);
locale.GetYearMonthDateFormats(*result.Obj());
return result;
}
collections::LazyList<WString> Localization::GetLongTimeFormats(Locale locale)
{
auto result = Ptr(new List<WString>);
locale.GetLongTimeFormats(*result.Obj());
return result;
}
collections::LazyList<WString> Localization::GetShortTimeFormats(Locale locale)
{
auto result = Ptr(new List<WString>);
locale.GetShortTimeFormats(*result.Obj());
return result;
}
WString Localization::GetShortDayOfWeekName(Locale locale, vint dayOfWeek)
{
return locale.GetShortDayOfWeekName(dayOfWeek);
}
WString Localization::GetLongDayOfWeekName(Locale locale, vint dayOfWeek)
{
return locale.GetLongDayOfWeekName(dayOfWeek);
}
WString Localization::GetShortMonthName(Locale locale, vint month)
{
return locale.GetShortMonthName(month);
}
WString Localization::GetLongMonthName(Locale locale, vint month)
{
return locale.GetLongMonthName(month);
}
WString Localization::FormatDate(Locale locale, const WString& format, DateTime date)
{
return locale.FormatDate(format, date);
}
WString Localization::FormatTime(Locale locale, const WString& format, DateTime date)
{
return locale.FormatTime(format, date);
}
WString Localization::FormatNumber(Locale locale, const WString& number)
{
return locale.FormatNumber(number);
}
WString Localization::FormatCurrency(Locale locale, const WString& number)
{
return locale.FormatCurrency(number);
}
/***********************************************************************
Versioning
***********************************************************************/
Versioning::Versioning()
{
}
Versioning::~Versioning()
{
}
vint Versioning::AllocateVersion()
{
return ++version;
}
vint Versioning::GetVersion()
{
return version;
}
}
}
}
/***********************************************************************
.\WFLIBRARYREFLECTION.CPP
***********************************************************************/
#include <limits.h>
#include <float.h>
namespace vl
{
using namespace collections;
using namespace regex;
namespace reflection
{
namespace description
{
/***********************************************************************
TypeName
***********************************************************************/
#ifndef VCZH_DEBUG_NO_REFLECTION
IMPL_TYPE_INFO_RENAME(vl::reflection::description::Sys, system::Sys)
IMPL_TYPE_INFO_RENAME(vl::reflection::description::Math, system::Math)
IMPL_TYPE_INFO_RENAME(vl::reflection::description::Localization, system::Localization)
IMPL_TYPE_INFO_RENAME(vl::reflection::description::CoroutineStatus, system::CoroutineStatus)
IMPL_TYPE_INFO_RENAME(vl::reflection::description::CoroutineResult, system::CoroutineResult)
IMPL_TYPE_INFO_RENAME(vl::reflection::description::ICoroutine, system::Coroutine)
IMPL_TYPE_INFO_RENAME(vl::reflection::description::EnumerableCoroutine::IImpl, system::EnumerableCoroutine::IImpl)
IMPL_TYPE_INFO_RENAME(vl::reflection::description::EnumerableCoroutine, system::EnumerableCoroutine)
IMPL_TYPE_INFO_RENAME(vl::reflection::description::AsyncStatus, system::AsyncStatus)
IMPL_TYPE_INFO_RENAME(vl::reflection::description::AsyncContext, system::AsyncContext)
IMPL_TYPE_INFO_RENAME(vl::reflection::description::IAsync, system::Async)
IMPL_TYPE_INFO_RENAME(vl::reflection::description::IPromise, system::Promise)
IMPL_TYPE_INFO_RENAME(vl::reflection::description::IFuture, system::Future)
IMPL_TYPE_INFO_RENAME(vl::reflection::description::IAsyncScheduler, system::AsyncScheduler)
IMPL_TYPE_INFO_RENAME(vl::reflection::description::AsyncCoroutine::IImpl, system::AsyncCoroutine::IImpl)
IMPL_TYPE_INFO_RENAME(vl::reflection::description::AsyncCoroutine, system::AsyncCoroutine)
IMPL_TYPE_INFO_RENAME(vl::reflection::description::StateMachine, system::StateMachine)
IMPL_TYPE_INFO_RENAME(vl::reflection::description::Versioning, system::Versioning)
IMPL_TYPE_INFO_RENAME(vl::rpc_controller::RpcObjectReference, system::RpcObjectReference)
IMPL_TYPE_INFO_RENAME(vl::rpc_controller::RpcException, system::RpcException)
IMPL_TYPE_INFO_RENAME(vl::rpc_controller::RpcByvalReturnValue, system::RpcByvalReturnValue)
IMPL_TYPE_INFO_RENAME(vl::rpc_controller::IRpcSerializer, system::IRpcSerializer)
IMPL_TYPE_INFO_RENAME(vl::rpc_controller::IRpcJsonMessageDispatcher::RequestType, system::IRpcJsonMessageDispatcher::RequestType)
IMPL_TYPE_INFO_RENAME(vl::rpc_controller::IRpcJsonMessageDispatcher, system::IRpcJsonMessageDispatcher)
IMPL_TYPE_INFO_RENAME(vl::rpc_controller::IRpcListOps, system::IRpcListOps)
IMPL_TYPE_INFO_RENAME(vl::rpc_controller::IRpcListEventOps, system::IRpcListEventOps)
IMPL_TYPE_INFO_RENAME(vl::rpc_controller::IRpcObjectOps, system::IRpcObjectOps)
IMPL_TYPE_INFO_RENAME(vl::rpc_controller::IRpcObjectEventOps, system::IRpcObjectEventOps)
IMPL_TYPE_INFO_RENAME(vl::rpc_controller::IRpcOperations, system::IRpcOperations)
IMPL_TYPE_INFO_RENAME(vl::rpc_controller::IRpcDispatcher, system::IRpcDispatcher)
IMPL_TYPE_INFO_RENAME(vl::rpc_controller::IRpcController, system::IRpcController)
IMPL_TYPE_INFO_RENAME(vl::rpc_controller::IRpcLifecycle, system::IRpcLifecycle)
IMPL_TYPE_INFO_RENAME(vl::rpc_controller::IRpcWrapperBase, system::IRpcWrapperBase)
IMPL_TYPE_INFO_RENAME(vl::rpc_controller::RpcByrefEnumerator, system::RpcByrefEnumerator)
IMPL_TYPE_INFO_RENAME(vl::rpc_controller::RpcByrefEnumerable, system::RpcByrefEnumerable)
IMPL_TYPE_INFO_RENAME(vl::rpc_controller::RpcByrefReadonlyList, system::RpcByrefReadonlyList)
IMPL_TYPE_INFO_RENAME(vl::rpc_controller::RpcByrefList, system::RpcByrefList)
IMPL_TYPE_INFO_RENAME(vl::rpc_controller::RpcByrefArray, system::RpcByrefArray)
IMPL_TYPE_INFO_RENAME(vl::rpc_controller::RpcByrefObservableList, system::RpcByrefObservableList)
IMPL_TYPE_INFO_RENAME(vl::rpc_controller::RpcByrefDictionary, system::RpcByrefDictionary)
IMPL_TYPE_INFO_RENAME(vl::__vwsn::att_cpp_File, system::workflow_attributes::att_cpp_File)
IMPL_TYPE_INFO_RENAME(vl::__vwsn::att_cpp_UserImpl, system::workflow_attributes::att_cpp_UserImpl)
IMPL_TYPE_INFO_RENAME(vl::__vwsn::att_cpp_Private, system::workflow_attributes::att_cpp_Private)
IMPL_TYPE_INFO_RENAME(vl::__vwsn::att_cpp_Protected, system::workflow_attributes::att_cpp_Protected)
IMPL_TYPE_INFO_RENAME(vl::__vwsn::att_cpp_Friend, system::workflow_attributes::att_cpp_Friend)
IMPL_TYPE_INFO_RENAME(vl::__vwsn::att_rpc_Interface, system::workflow_attributes::att_rpc_Interface)
IMPL_TYPE_INFO_RENAME(vl::__vwsn::att_rpc_Ctor, system::workflow_attributes::att_rpc_Ctor)
IMPL_TYPE_INFO_RENAME(vl::__vwsn::att_rpc_Byval, system::workflow_attributes::att_rpc_Byval)
IMPL_TYPE_INFO_RENAME(vl::__vwsn::att_rpc_Byref, system::workflow_attributes::att_rpc_Byref)
IMPL_TYPE_INFO_RENAME(vl::__vwsn::att_rpc_Cached, system::workflow_attributes::att_rpc_Cached)
IMPL_TYPE_INFO_RENAME(vl::__vwsn::att_rpc_Dynamic, system::workflow_attributes::att_rpc_Dynamic)
IMPL_TYPE_INFO_RENAME(vl::__vwsn::att_rpc_IdString, system::workflow_attributes::att_rpc_IdString)
IMPL_TYPE_INFO_RENAME(vl::__vwsn::att_rpc_IdNumber, system::workflow_attributes::att_rpc_IdNumber)
#endif
/***********************************************************************
WfLoadLibraryTypes
***********************************************************************/
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
#define _ ,
BEGIN_STRUCT_MEMBER(vl::__vwsn::att_cpp_File)
STRUCT_MEMBER(argument)
END_STRUCT_MEMBER(vl::__vwsn::att_cpp_File)
BEGIN_STRUCT_MEMBER(vl::__vwsn::att_cpp_UserImpl)
END_STRUCT_MEMBER(vl::__vwsn::att_cpp_UserImpl)
BEGIN_STRUCT_MEMBER(vl::__vwsn::att_cpp_Private)
END_STRUCT_MEMBER(vl::__vwsn::att_cpp_Private)
BEGIN_STRUCT_MEMBER(vl::__vwsn::att_cpp_Protected)
END_STRUCT_MEMBER(vl::__vwsn::att_cpp_Protected)
BEGIN_STRUCT_MEMBER(vl::__vwsn::att_cpp_Friend)
STRUCT_MEMBER(argument)
END_STRUCT_MEMBER(vl::__vwsn::att_cpp_Friend)
BEGIN_STRUCT_MEMBER(vl::__vwsn::att_rpc_Interface)
END_STRUCT_MEMBER(vl::__vwsn::att_rpc_Interface)
BEGIN_STRUCT_MEMBER(vl::__vwsn::att_rpc_Ctor)
END_STRUCT_MEMBER(vl::__vwsn::att_rpc_Ctor)
BEGIN_STRUCT_MEMBER(vl::__vwsn::att_rpc_Byval)
END_STRUCT_MEMBER(vl::__vwsn::att_rpc_Byval)
BEGIN_STRUCT_MEMBER(vl::__vwsn::att_rpc_Byref)
END_STRUCT_MEMBER(vl::__vwsn::att_rpc_Byref)
BEGIN_STRUCT_MEMBER(vl::__vwsn::att_rpc_Cached)
END_STRUCT_MEMBER(vl::__vwsn::att_rpc_Cached)
BEGIN_STRUCT_MEMBER(vl::__vwsn::att_rpc_Dynamic)
END_STRUCT_MEMBER(vl::__vwsn::att_rpc_Dynamic)
BEGIN_STRUCT_MEMBER(vl::__vwsn::att_rpc_IdString)
STRUCT_MEMBER(argument)
END_STRUCT_MEMBER(vl::__vwsn::att_rpc_IdString)
BEGIN_STRUCT_MEMBER(vl::__vwsn::att_rpc_IdNumber)
STRUCT_MEMBER(argument)
END_STRUCT_MEMBER(vl::__vwsn::att_rpc_IdNumber)
BEGIN_STRUCT_MEMBER(vl::rpc_controller::RpcObjectReference)
STRUCT_MEMBER(clientId)
STRUCT_MEMBER(objectId)
STRUCT_MEMBER(typeId)
END_STRUCT_MEMBER(vl::rpc_controller::RpcObjectReference)
BEGIN_STRUCT_MEMBER(vl::rpc_controller::RpcException)
STRUCT_MEMBER(message)
END_STRUCT_MEMBER(vl::rpc_controller::RpcException)
BEGIN_CLASS_MEMBER(vl::rpc_controller::RpcByvalReturnValue)
CLASS_MEMBER_CONSTRUCTOR(Ptr<vl::rpc_controller::RpcByvalReturnValue>(), NO_PARAMETER)
CLASS_MEMBER_FIELD(value)
CLASS_MEMBER_FIELD(slot)
END_CLASS_MEMBER(vl::rpc_controller::RpcByvalReturnValue)
BEGIN_INTERFACE_MEMBER(vl::rpc_controller::IRpcSerializer)
CLASS_MEMBER_METHOD(Serialize, { L"value" })
CLASS_MEMBER_METHOD(Deserialize, { L"value" })
END_INTERFACE_MEMBER(vl::rpc_controller::IRpcSerializer)
BEGIN_ENUM_ITEM(vl::rpc_controller::IRpcJsonMessageDispatcher::RequestType)
ENUM_CLASS_ITEM(Direct)
ENUM_CLASS_ITEM(Broadcast)
ENUM_CLASS_ITEM(BroadcastAndDrop)
END_ENUM_ITEM(vl::rpc_controller::IRpcJsonMessageDispatcher::RequestType)
BEGIN_INTERFACE_MEMBER(vl::rpc_controller::IRpcJsonMessageDispatcher)
CLASS_MEMBER_METHOD(AllocateRequestId, NO_PARAMETER)
CLASS_MEMBER_METHOD(OnJsonRequest, { L"message" _ L"requestType" })
END_INTERFACE_MEMBER(vl::rpc_controller::IRpcJsonMessageDispatcher)
BEGIN_INTERFACE_MEMBER(vl::rpc_controller::IRpcListOps)
CLASS_MEMBER_METHOD(EnumCreate, { L"ref" })
CLASS_MEMBER_METHOD(EnumNext, { L"enumerator" })
CLASS_MEMBER_METHOD(EnumGetCurrent, { L"enumerator" })
CLASS_MEMBER_METHOD(ListGetCount, { L"ref" })
CLASS_MEMBER_METHOD(ListGet, { L"ref" _ L"index" })
CLASS_MEMBER_METHOD(ListSet, { L"ref" _ L"index" _ L"value" })
CLASS_MEMBER_METHOD(ListAdd, { L"ref" _ L"value" })
CLASS_MEMBER_METHOD(ListInsert, { L"ref" _ L"index" _ L"value" })
CLASS_MEMBER_METHOD(ListRemoveAt, { L"ref" _ L"index" })
CLASS_MEMBER_METHOD(ListClear, { L"ref" })
CLASS_MEMBER_METHOD(ListContains, { L"ref" _ L"value" })
CLASS_MEMBER_METHOD(ListIndexOf, { L"ref" _ L"value" })
CLASS_MEMBER_METHOD(ArrayResize, { L"ref" _ L"size" })
CLASS_MEMBER_METHOD(DictGetCount, { L"ref" })
CLASS_MEMBER_METHOD(DictGet, { L"ref" _ L"key" })
CLASS_MEMBER_METHOD(DictSet, { L"ref" _ L"key" _ L"value" })
CLASS_MEMBER_METHOD(DictRemove, { L"ref" _ L"key" })
CLASS_MEMBER_METHOD(DictClear, { L"ref" })
CLASS_MEMBER_METHOD(DictContainsKey, { L"ref" _ L"key" })
CLASS_MEMBER_METHOD(DictGetKeys, { L"ref" })
CLASS_MEMBER_METHOD(DictGetValues, { L"ref" })
END_INTERFACE_MEMBER(vl::rpc_controller::IRpcListOps)
BEGIN_INTERFACE_MEMBER(vl::rpc_controller::IRpcListEventOps)
CLASS_MEMBER_METHOD(OnItemChanged, { L"ref" _ L"index" _ L"oldCount" _ L"newCount" })
END_INTERFACE_MEMBER(vl::rpc_controller::IRpcListEventOps)
BEGIN_INTERFACE_MEMBER(vl::rpc_controller::IRpcObjectOps)
CLASS_MEMBER_METHOD(InvokeMethod, { L"ref" _ L"methodId" _ L"arguments" })
CLASS_MEMBER_METHOD(EndInvokeMethod, { L"slot" })
CLASS_MEMBER_METHOD(ObjectHold, { L"ref" _ L"remoteClientId" _ L"hold" })
END_INTERFACE_MEMBER(vl::rpc_controller::IRpcObjectOps)
BEGIN_INTERFACE_MEMBER(vl::rpc_controller::IRpcObjectEventOps)
CLASS_MEMBER_METHOD(InvokeEvent, { L"ref" _ L"eventId" _ L"arguments" })
END_INTERFACE_MEMBER(vl::rpc_controller::IRpcObjectEventOps)
BEGIN_INTERFACE_MEMBER_NOPROXY(vl::rpc_controller::IRpcOperations)
CLASS_MEMBER_PROPERTY_READONLY_FAST(ObjectOps)
CLASS_MEMBER_PROPERTY_READONLY_FAST(ObjectEventOps)
END_INTERFACE_MEMBER(vl::rpc_controller::IRpcOperations)
BEGIN_INTERFACE_MEMBER_NOPROXY(vl::rpc_controller::IRpcDispatcher)
CLASS_MEMBER_METHOD(Finalize, NO_PARAMETER)
CLASS_MEMBER_METHOD(Initialize, NO_PARAMETER)
CLASS_MEMBER_METHOD(DeclareLocalService, { L"ref" })
CLASS_MEMBER_METHOD(BroadcastFromClient_ObjectEventOps, { L"selfClientId" })
CLASS_MEMBER_METHOD(SendToClient_ObjectOps, { L"targetClientId" })
END_INTERFACE_MEMBER(vl::rpc_controller::IRpcDispatcher)
BEGIN_INTERFACE_MEMBER_NOPROXY(vl::rpc_controller::IRpcController)
CLASS_MEMBER_BASE(vl::rpc_controller::IRpcOperations)
CLASS_MEMBER_METHOD(Finalize, NO_PARAMETER)
CLASS_MEMBER_METHOD(SetEventSuppressedFlag, { L"ref" _ L"eventId" _ L"suppressed" })
CLASS_MEMBER_METHOD(GetEventSuppressedFlag, { L"ref" _ L"eventId" })
CLASS_MEMBER_METHOD(SetItemChangedSuppressedFlag, { L"ref" _ L"suppressed" })
CLASS_MEMBER_METHOD(GetItemChangedSuppressedFlag, { L"ref" })
END_INTERFACE_MEMBER(vl::rpc_controller::IRpcController)
BEGIN_INTERFACE_MEMBER_NOPROXY(vl::rpc_controller::IRpcLifecycle)
CLASS_MEMBER_METHOD(Finalize, NO_PARAMETER)
CLASS_MEMBER_METHOD(Initialize, NO_PARAMETER)
CLASS_MEMBER_PROPERTY_READONLY_FAST(ClientId)
CLASS_MEMBER_PROPERTY_READONLY_FAST(Dispatcher)
CLASS_MEMBER_PROPERTY_READONLY_FAST(Controller)
CLASS_MEMBER_PROPERTY_READONLY_FAST(Serializer)
CLASS_MEMBER_METHOD(RefToPtr, { L"ref" })
CLASS_MEMBER_METHOD(PtrToRef, { L"obj" })
CLASS_MEMBER_METHOD(LocalObjectHold, { L"ref" _ L"remoteClientId" })
CLASS_MEMBER_METHOD(LocalObjectUnhold, { L"ref" _ L"remoteClientId" })
CLASS_MEMBER_METHOD(RegisterLocalService, { L"typeId" _ L"service" })
CLASS_MEMBER_METHOD(DeclareRemoteService, { L"ref" })
CLASS_MEMBER_METHOD(GetTypeIdFromName, { L"typeName" })
CLASS_MEMBER_METHOD(RequestService, { L"typeName" })
CLASS_MEMBER_STATIC_EXTERNALMETHOD(RpcBoxByref, { L"trivial" _ L"lc" }, vl::rpc_controller::RpcObjectReference(*)(vl::Ptr<vl::reflection::IDescriptable>, vl::rpc_controller::IRpcLifecycle*), vl::rpc_controller::RpcBoxByref)
CLASS_MEMBER_STATIC_EXTERNALMETHOD(RpcUnboxByref, { L"serializable" _ L"lc" }, vl::Ptr<vl::reflection::IDescriptable>(*)(vl::rpc_controller::RpcObjectReference, vl::rpc_controller::IRpcLifecycle*), vl::rpc_controller::RpcUnboxByref)
CLASS_MEMBER_STATIC_EXTERNALMETHOD(RpcCopyByval, { L"trivial" _ L"lc" }, Value(*)(const Value&, vl::rpc_controller::IRpcLifecycle*), vl::rpc_controller::RpcCopyByval)
CLASS_MEMBER_STATIC_EXTERNALMETHOD(RpcBoxByval, { L"trivial" _ L"lc" }, Value(*)(const Value&, vl::rpc_controller::IRpcLifecycle*), vl::rpc_controller::RpcBoxByval)
CLASS_MEMBER_STATIC_EXTERNALMETHOD(RpcUnboxByval, { L"serializable" _ L"lc" }, vl::Ptr<vl::reflection::IDescriptable>(*)(const Value&, vl::rpc_controller::IRpcLifecycle*), vl::rpc_controller::RpcUnboxByval)
CLASS_MEMBER_STATIC_EXTERNALMETHOD(ReadMethodException, { L"value" }, void(*)(const Value&), vl::rpc_controller::ReadMethodException)
CLASS_MEMBER_STATIC_EXTERNALMETHOD(ReadEventException, { L"exceptions" }, void(*)(vl::rpc_controller::RpcEventExceptionMap), vl::rpc_controller::ReadEventException)
CLASS_MEMBER_STATIC_EXTERNALMETHOD(JsonSerializePredefinedTypes, { L"value" _ L"rpcjson_Serialize" }, vl::Ptr<vl::glr::json::JsonNode>(*)(const Value&, const vl::rpc_controller::RpcJsonSerializeCallback&), vl::rpc_controller::JsonSerializePredefinedTypes)
CLASS_MEMBER_STATIC_EXTERNALMETHOD(JsonDeserializePredefinedTypes, { L"value" _ L"rpcjson_Deserialize" }, Value(*)(const Value&, const vl::rpc_controller::RpcJsonDeserializeCallback&), vl::rpc_controller::JsonDeserializePredefinedTypes)
END_INTERFACE_MEMBER(vl::rpc_controller::IRpcLifecycle)
BEGIN_INTERFACE_MEMBER(vl::rpc_controller::IRpcWrapperBase)
CLASS_MEMBER_METHOD(DisconnectFromLifecycle, NO_PARAMETER)
END_INTERFACE_MEMBER(vl::rpc_controller::IRpcWrapperBase)
BEGIN_CLASS_MEMBER(vl::rpc_controller::RpcByrefEnumerator)
CLASS_MEMBER_BASE(vl::reflection::description::IValueEnumerator)
CLASS_MEMBER_BASE(vl::rpc_controller::IRpcWrapperBase)
END_CLASS_MEMBER(vl::rpc_controller::RpcByrefEnumerator)
BEGIN_CLASS_MEMBER(vl::rpc_controller::RpcByrefEnumerable)
CLASS_MEMBER_BASE(vl::reflection::description::IValueEnumerable)
CLASS_MEMBER_BASE(vl::rpc_controller::IRpcWrapperBase)
END_CLASS_MEMBER(vl::rpc_controller::RpcByrefEnumerable)
BEGIN_CLASS_MEMBER(vl::rpc_controller::RpcByrefReadonlyList)
CLASS_MEMBER_BASE(vl::reflection::description::IValueReadonlyList)
CLASS_MEMBER_BASE(vl::rpc_controller::IRpcWrapperBase)
END_CLASS_MEMBER(vl::rpc_controller::RpcByrefReadonlyList)
BEGIN_CLASS_MEMBER(vl::rpc_controller::RpcByrefList)
CLASS_MEMBER_BASE(vl::rpc_controller::RpcByrefReadonlyList)
CLASS_MEMBER_BASE(vl::reflection::description::IValueList)
END_CLASS_MEMBER(vl::rpc_controller::RpcByrefList)
BEGIN_CLASS_MEMBER(vl::rpc_controller::RpcByrefArray)
CLASS_MEMBER_BASE(vl::reflection::description::IValueArray)
CLASS_MEMBER_BASE(vl::rpc_controller::IRpcWrapperBase)
END_CLASS_MEMBER(vl::rpc_controller::RpcByrefArray)
BEGIN_CLASS_MEMBER(vl::rpc_controller::RpcByrefObservableList)
CLASS_MEMBER_BASE(vl::reflection::description::IValueObservableList)
CLASS_MEMBER_BASE(vl::rpc_controller::IRpcWrapperBase)
END_CLASS_MEMBER(vl::rpc_controller::RpcByrefObservableList)
BEGIN_CLASS_MEMBER(vl::rpc_controller::RpcByrefDictionary)
CLASS_MEMBER_BASE(vl::reflection::description::IValueDictionary)
CLASS_MEMBER_BASE(vl::rpc_controller::IRpcWrapperBase)
END_CLASS_MEMBER(vl::rpc_controller::RpcByrefDictionary)
BEGIN_CLASS_MEMBER(Sys)
CLASS_MEMBER_STATIC_METHOD(Int32ToInt, { L"value" })
CLASS_MEMBER_STATIC_METHOD(Int64ToInt, { L"value" })
CLASS_MEMBER_STATIC_METHOD(IntToInt32, { L"value" })
CLASS_MEMBER_STATIC_METHOD(IntToInt64, { L"value" })
CLASS_MEMBER_STATIC_METHOD(UInt32ToUInt, { L"value" })
CLASS_MEMBER_STATIC_METHOD(UInt64ToUInt, { L"value" })
CLASS_MEMBER_STATIC_METHOD(UIntToUInt32, { L"value" })
CLASS_MEMBER_STATIC_METHOD(UIntToUInt64, { L"value" })
CLASS_MEMBER_STATIC_METHOD(Len, { L"value" })
CLASS_MEMBER_STATIC_METHOD(Left, { L"value" _ L"length" })
CLASS_MEMBER_STATIC_METHOD(Right, { L"value" _ L"length" })
CLASS_MEMBER_STATIC_METHOD(Mid, { L"value" _ L"start" _ L"length" })
CLASS_MEMBER_STATIC_METHOD(Find, { L"value" _ L"substr" })
CLASS_MEMBER_STATIC_METHOD(UCase, { L"value" })
CLASS_MEMBER_STATIC_METHOD(LCase, { L"value" })
CLASS_MEMBER_STATIC_METHOD(LoremIpsumTitle, { L"bestLength" })
CLASS_MEMBER_STATIC_METHOD(LoremIpsumSentence, { L"bestLength" })
CLASS_MEMBER_STATIC_METHOD(LoremIpsumParagraph, { L"bestLength" })
CLASS_MEMBER_STATIC_METHOD(ReverseEnumerable, { L"value" })
#pragma push_macro("CompareString")
#if defined CompareString
#undef CompareString
#endif
#define DEFINE_COMPARE(TYPE) CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Compare, PROTECT_PARAMETERS({L"a" _ L"b"}), vint(*)(TYPE, TYPE))
REFLECTION_PREDEFINED_PRIMITIVE_TYPES(DEFINE_COMPARE)
DEFINE_COMPARE(DateTime)
#undef DEFINE_COMPARE
#pragma pop_macro("CompareString")
CLASS_MEMBER_STATIC_METHOD(GetLocalTime, NO_PARAMETER)
CLASS_MEMBER_STATIC_METHOD(GetUtcTime, NO_PARAMETER)
CLASS_MEMBER_STATIC_METHOD(ToLocalTime, { L"dt" })
CLASS_MEMBER_STATIC_METHOD(ToUtcTime, { L"dt" })
CLASS_MEMBER_STATIC_METHOD(Forward, { L"dt" _ L"milliseconds" })
CLASS_MEMBER_STATIC_METHOD(Backward, { L"dt" _ L"milliseconds" })
CLASS_MEMBER_STATIC_METHOD_OVERLOAD(CreateDateTime, {L"year" _ L"month" _ L"day" }, DateTime(*)(vint, vint, vint))
CLASS_MEMBER_STATIC_METHOD_OVERLOAD(CreateDateTime, { L"year" _ L"month" _ L"day" _ L"hour" _ L"minute" _ L"second" _ L"milliseconds" }, DateTime(*)(vint, vint, vint, vint, vint, vint, vint))
END_CLASS_MEMBER(Sys)
BEGIN_CLASS_MEMBER(Math)
CLASS_MEMBER_STATIC_METHOD(Pi, NO_PARAMETER)
CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Abs, { L"value" }, vint8_t(*)(vint8_t))
CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Abs, { L"value" }, vint16_t(*)(vint16_t))
CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Abs, { L"value" }, vint32_t(*)(vint32_t))
CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Abs, { L"value" }, vint64_t(*)(vint64_t))
CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Abs, { L"value" }, float(*)(float))
CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Abs, { L"value" }, double(*)(double))
#define DEFINE_MINMAX(TYPE)\
CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Min, PROTECT_PARAMETERS({L"a" _ L"b"}), TYPE(*)(TYPE, TYPE))\
CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Max, PROTECT_PARAMETERS({L"a" _ L"b"}), TYPE(*)(TYPE, TYPE))\
REFLECTION_PREDEFINED_PRIMITIVE_TYPES(DEFINE_MINMAX)
DEFINE_MINMAX(DateTime)
#undef DEFINE_MINMAX
CLASS_MEMBER_STATIC_METHOD(Sin, { L"value" })
CLASS_MEMBER_STATIC_METHOD(Cos, { L"value" })
CLASS_MEMBER_STATIC_METHOD(Tan, { L"value" })
CLASS_MEMBER_STATIC_METHOD(ASin, { L"value" })
CLASS_MEMBER_STATIC_METHOD(ACos, { L"value" })
CLASS_MEMBER_STATIC_METHOD(ATan, { L"value" })
CLASS_MEMBER_STATIC_METHOD(ATan2, { L"x" _ L"y" })
CLASS_MEMBER_STATIC_METHOD(Exp, { L"value" })
CLASS_MEMBER_STATIC_METHOD(LogN, { L"value" })
CLASS_MEMBER_STATIC_METHOD(Log10, { L"value" })
CLASS_MEMBER_STATIC_METHOD(Log, { L"value" _ L"base" })
CLASS_MEMBER_STATIC_METHOD(Pow, { L"value" _ L"power" })
CLASS_MEMBER_STATIC_METHOD(Ceil, { L"value" })
CLASS_MEMBER_STATIC_METHOD(Floor, { L"value" })
CLASS_MEMBER_STATIC_METHOD(Round, { L"value" })
CLASS_MEMBER_STATIC_METHOD(Trunc, { L"value" })
END_CLASS_MEMBER(Math)
BEGIN_CLASS_MEMBER(Localization)
CLASS_MEMBER_STATIC_METHOD(Invariant, NO_PARAMETER)
CLASS_MEMBER_STATIC_METHOD(System, NO_PARAMETER)
CLASS_MEMBER_STATIC_METHOD(User, NO_PARAMETER)
CLASS_MEMBER_STATIC_METHOD(Locales, NO_PARAMETER)
CLASS_MEMBER_STATIC_METHOD(GetShortDateFormats, { L"locale" })
CLASS_MEMBER_STATIC_METHOD(GetLongDateFormats, { L"locale" })
CLASS_MEMBER_STATIC_METHOD(GetYearMonthDateFormats, { L"locale" })
CLASS_MEMBER_STATIC_METHOD(GetLongTimeFormats, { L"locale" })
CLASS_MEMBER_STATIC_METHOD(GetShortTimeFormats, { L"locale" })
CLASS_MEMBER_STATIC_METHOD(GetShortDayOfWeekName, { L"locale" _ L"dayOfWeek" })
CLASS_MEMBER_STATIC_METHOD(GetLongDayOfWeekName, { L"locale" _ L"dayOfWeek" })
CLASS_MEMBER_STATIC_METHOD(GetShortMonthName, { L"locale" _ L"month" })
CLASS_MEMBER_STATIC_METHOD(GetLongMonthName, { L"locale" _ L"month" })
CLASS_MEMBER_STATIC_METHOD(FormatDate, { L"locale" _ L"format" _ L"date" })
CLASS_MEMBER_STATIC_METHOD(FormatTime, { L"locale" _ L"format" _ L"date" })
CLASS_MEMBER_STATIC_METHOD(FormatNumber, { L"locale" _ L"number" })
CLASS_MEMBER_STATIC_METHOD(FormatCurrency, { L"locale" _ L"number" })
END_CLASS_MEMBER(Localization)
BEGIN_ENUM_ITEM(CoroutineStatus)
ENUM_CLASS_ITEM(Waiting)
ENUM_CLASS_ITEM(Executing)
ENUM_CLASS_ITEM(Stopped)
END_ENUM_ITEM(CoroutineStatus)
BEGIN_INTERFACE_MEMBER(ICoroutine)
CLASS_MEMBER_METHOD(Resume, { L"raiseException" _ L"output" })
CLASS_MEMBER_PROPERTY_READONLY_FAST(Failure)
CLASS_MEMBER_PROPERTY_READONLY_FAST(Status)
END_INTERFACE_MEMBER(ICoroutine)
BEGIN_CLASS_MEMBER(CoroutineResult)
CLASS_MEMBER_CONSTRUCTOR(Ptr<CoroutineResult>(), NO_PARAMETER)
CLASS_MEMBER_PROPERTY_FAST(Result)
CLASS_MEMBER_PROPERTY_FAST(Failure)
END_CLASS_MEMBER(CoroutineResult)
BEGIN_INTERFACE_MEMBER_NOPROXY(EnumerableCoroutine::IImpl)
CLASS_MEMBER_BASE(IValueEnumerator)
END_INTERFACE_MEMBER(EnumerableCoroutine::IImpl)
BEGIN_CLASS_MEMBER(EnumerableCoroutine)
CLASS_MEMBER_STATIC_METHOD(YieldAndPause, { L"impl" _ L"value" })
CLASS_MEMBER_STATIC_METHOD(JoinAndPause, { L"impl" _ L"value" })
CLASS_MEMBER_STATIC_METHOD(ReturnAndExit, { L"impl" })
CLASS_MEMBER_STATIC_METHOD(Create, { L"creator" })
END_CLASS_MEMBER(EnumerableCoroutine)
BEGIN_ENUM_ITEM(AsyncStatus)
ENUM_CLASS_ITEM(Ready)
ENUM_CLASS_ITEM(Executing)
ENUM_CLASS_ITEM(Stopped)
END_ENUM_ITEM(AsyncStatus)
BEGIN_CLASS_MEMBER(AsyncContext)
CLASS_MEMBER_CONSTRUCTOR(Ptr<AsyncContext>(const Value&), {L"context"})
CLASS_MEMBER_METHOD(IsCancelled, NO_PARAMETER)
CLASS_MEMBER_METHOD(Cancel, NO_PARAMETER)
CLASS_MEMBER_PROPERTY_FAST(Context)
END_CLASS_MEMBER(AsyncContext)
BEGIN_INTERFACE_MEMBER(IAsync)
CLASS_MEMBER_PROPERTY_READONLY_FAST(Status)
CLASS_MEMBER_METHOD(Execute, { L"callback" _ L"context" })
CLASS_MEMBER_STATIC_METHOD(Delay, { L"milliseconds" })
END_INTERFACE_MEMBER(IAsync)
BEGIN_INTERFACE_MEMBER_NOPROXY(IPromise)
CLASS_MEMBER_METHOD(SendResult, { L"result" })
CLASS_MEMBER_METHOD(SendFailure, { L"failure" })
END_INTERFACE_MEMBER(IPromise)
BEGIN_INTERFACE_MEMBER_NOPROXY(IFuture)
CLASS_MEMBER_BASE(IAsync)
CLASS_MEMBER_BASE(IPromise)
CLASS_MEMBER_PROPERTY_READONLY_FAST(Promise)
CLASS_MEMBER_STATIC_METHOD(Create, NO_PARAMETER)
END_INTERFACE_MEMBER(IFuture)
BEGIN_INTERFACE_MEMBER_NOPROXY(IAsyncScheduler)
CLASS_MEMBER_METHOD(Execute, { L"callback" })
CLASS_MEMBER_METHOD(ExecuteInBackground, { L"callback" })
CLASS_MEMBER_METHOD(DelayExecute, { L"callback" _ L"milliseconds" })
CLASS_MEMBER_STATIC_METHOD(GetSchedulerForCurrentThread, NO_PARAMETER)
END_INTERFACE_MEMBER(IAsyncScheduler)
BEGIN_INTERFACE_MEMBER_NOPROXY(AsyncCoroutine::IImpl)
CLASS_MEMBER_BASE(IAsync)
END_INTERFACE_MEMBER(AsyncCoroutine::IImpl)
BEGIN_CLASS_MEMBER(AsyncCoroutine)
CLASS_MEMBER_STATIC_METHOD(AwaitAndRead, { L"impl" _ L"value" })
CLASS_MEMBER_STATIC_METHOD(ReturnAndExit, { L"impl" _ L"value"})
CLASS_MEMBER_STATIC_METHOD(QueryContext, { L"impl" })
CLASS_MEMBER_STATIC_METHOD(Create, { L"creator" })
CLASS_MEMBER_STATIC_METHOD(CreateAndRun, { L"creator" })
END_CLASS_MEMBER(AsyncCoroutine)
BEGIN_CLASS_MEMBER(StateMachine)
CLASS_MEMBER_FIELD(stateMachineInitialized)
CLASS_MEMBER_FIELD(stateMachineStopped)
CLASS_MEMBER_FIELD(stateMachineInput)
CLASS_MEMBER_FIELD(stateMachineCoroutine)
CLASS_MEMBER_CONSTRUCTOR(Ptr<StateMachine>(), NO_PARAMETER)
CLASS_MEMBER_METHOD(ResumeStateMachine, NO_PARAMETER)
CLASS_MEMBER_PROPERTY_READONLY_FAST(StateMachineStatus)
END_CLASS_MEMBER(StateMachine)
BEGIN_CLASS_MEMBER(Versioning)
CLASS_MEMBER_CONSTRUCTOR(Ptr<Versioning>(), NO_PARAMETER)
CLASS_MEMBER_METHOD(AllocateVersion, NO_PARAMETER)
CLASS_MEMBER_PROPERTY_READONLY_FAST(Version)
END_CLASS_MEMBER(Versioning)
#undef _
class WfLibraryTypeLoader : public Object, public ITypeLoader
{
public:
void Load(ITypeManager* manager)override
{
WORKFLOW_LIBRARY_TYPES(ADD_TYPE_INFO)
}
void Unload(ITypeManager* manager)override
{
}
};
#endif
bool WfLoadLibraryTypes()
{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
ITypeManager* manager = GetGlobalTypeManager();
if (manager)
{
auto loader = Ptr(new WfLibraryTypeLoader);
return manager->AddTypeLoader(loader);
}
#endif
return false;
}
}
}
}
/***********************************************************************
.\RPC\WFLIBRARYRPC.CPP
***********************************************************************/
namespace vl
{
namespace rpc_controller
{
using namespace collections;
using namespace reflection;
using namespace reflection::description;
namespace
{
#ifndef VCZH_WORKFLOW_RPC_OBJECT_REFERENCE_VALUE_HELPERS
#define VCZH_WORKFLOW_RPC_OBJECT_REFERENCE_VALUE_HELPERS
bool IsRpcObjectReferenceValue(const Value& value)
{
return value.GetValueType() == Value::BoxedValue && value.GetBoxedValue().Cast<IValueType::TypedBox<RpcObjectReference>>();
}
RpcObjectReference GetRpcObjectReference(const Value& value)
{
auto boxed = value.GetBoxedValue().Cast<IValueType::TypedBox<RpcObjectReference>>();
CHECK_ERROR(boxed, L"RpcObjectReference is expected.");
return boxed->value;
}
#endif
bool IsNullRpcObjectReference(RpcObjectReference ref)
{
return ref.clientId == RpcClientId_Invalid
&& ref.objectId == RpcObjectId_Invalid
&& ref.typeId == RpcTypeId_NotFound;
}
template<typename K, typename V>
bool ContainsKey(const Dictionary<K, V>& xs, const K& key)
{
return xs.Keys().Contains(key);
}
template<typename TInterface>
Ptr<TInterface> TryGetValueInterface(const Value& value)
{
if (auto raw = value.GetRawPtr())
{
return Ptr(dynamic_cast<TInterface*>(raw));
}
return nullptr;
}
Value RpcCopyValueByvalInternal(const Value& trivial, Dictionary<const DescriptableObject*, bool>& visited)
{
if (trivial.IsNull()) return trivial;
if (trivial.GetValueType() == Value::SharedPtr)
{
if (auto roDict = TryGetValueInterface<IValueReadonlyDictionary>(trivial))
{
auto key = static_cast<const DescriptableObject*>(trivial.GetRawPtr());
if (ContainsKey(visited, key)) CHECK_FAIL(L"Byval copying does not support cycles.");
visited.Add(key, true);
auto dict = IValueDictionary::Create();
auto keys = roDict->GetKeys();
for (vint i = 0; i < keys->GetCount(); i++)
{
auto dictKey = keys->Get(i);
dict->Set(
RpcCopyValueByvalInternal(dictKey, visited),
RpcCopyValueByvalInternal(roDict->Get(dictKey), visited)
);
}
visited.Remove(key);
return BoxValue(dict);
}
if (auto obsList = TryGetValueInterface<IValueObservableList>(trivial))
{
auto key = static_cast<const DescriptableObject*>(trivial.GetRawPtr());
if (ContainsKey(visited, key)) CHECK_FAIL(L"Byval copying does not support cycles.");
visited.Add(key, true);
auto list = IValueObservableList::Create();
for (vint i = 0; i < obsList->GetCount(); i++)
{
list->Add(RpcCopyValueByvalInternal(obsList->Get(i), visited));
}
visited.Remove(key);
return BoxValue(list);
}
if (auto array = TryGetValueInterface<IValueArray>(trivial))
{
auto key = static_cast<const DescriptableObject*>(trivial.GetRawPtr());
if (ContainsKey(visited, key)) CHECK_FAIL(L"Byval copying does not support cycles.");
visited.Add(key, true);
auto list = IValueArray::Create();
list->Resize(array->GetCount());
for (vint i = 0; i < array->GetCount(); i++)
{
list->Set(i, RpcCopyValueByvalInternal(array->Get(i), visited));
}
visited.Remove(key);
return BoxValue(list);
}
if (auto roList = TryGetValueInterface<IValueReadonlyList>(trivial))
{
auto key = static_cast<const DescriptableObject*>(trivial.GetRawPtr());
if (ContainsKey(visited, key)) CHECK_FAIL(L"Byval copying does not support cycles.");
visited.Add(key, true);
auto list = IValueList::Create();
for (vint i = 0; i < roList->GetCount(); i++)
{
list->Add(RpcCopyValueByvalInternal(roList->Get(i), visited));
}
visited.Remove(key);
return BoxValue(list);
}
}
return trivial;
}
Value RpcBoxValueByvalInternal(const Value& trivial, IRpcLifecycle* lc, Dictionary<const DescriptableObject*, bool>& visited)
{
if (trivial.IsNull()) return trivial;
if (trivial.GetValueType() == Value::SharedPtr)
{
if (auto roDict = TryGetValueInterface<IValueReadonlyDictionary>(trivial))
{
auto key = static_cast<const DescriptableObject*>(trivial.GetRawPtr());
if (ContainsKey(visited, key)) CHECK_FAIL(L"Byval boxing does not support cycles.");
visited.Add(key, true);
auto dict = IValueDictionary::Create();
auto keys = roDict->GetKeys();
for (vint i = 0; i < keys->GetCount(); i++)
{
auto dictKey = keys->Get(i);
dict->Set(
RpcBoxValueByvalInternal(dictKey, lc, visited),
RpcBoxValueByvalInternal(roDict->Get(dictKey), lc, visited)
);
}
visited.Remove(key);
return BoxValue(dict);
}
if (auto obsList = TryGetValueInterface<IValueObservableList>(trivial))
{
auto key = static_cast<const DescriptableObject*>(trivial.GetRawPtr());
if (ContainsKey(visited, key)) CHECK_FAIL(L"Byval boxing does not support cycles.");
visited.Add(key, true);
auto list = IValueObservableList::Create();
for (vint i = 0; i < obsList->GetCount(); i++)
{
list->Add(RpcBoxValueByvalInternal(obsList->Get(i), lc, visited));
}
visited.Remove(key);
return BoxValue(list);
}
if (auto array = TryGetValueInterface<IValueArray>(trivial))
{
auto key = static_cast<const DescriptableObject*>(trivial.GetRawPtr());
if (ContainsKey(visited, key)) CHECK_FAIL(L"Byval boxing does not support cycles.");
visited.Add(key, true);
auto list = IValueArray::Create();
list->Resize(array->GetCount());
for (vint i = 0; i < array->GetCount(); i++)
{
list->Set(i, RpcBoxValueByvalInternal(array->Get(i), lc, visited));
}
visited.Remove(key);
return BoxValue(list);
}
if (auto roList = TryGetValueInterface<IValueReadonlyList>(trivial))
{
auto key = static_cast<const DescriptableObject*>(trivial.GetRawPtr());
if (ContainsKey(visited, key)) CHECK_FAIL(L"Byval boxing does not support cycles.");
visited.Add(key, true);
auto list = IValueList::Create();
for (vint i = 0; i < roList->GetCount(); i++)
{
list->Add(RpcBoxValueByvalInternal(roList->Get(i), lc, visited));
}
visited.Remove(key);
return BoxValue(list);
}
if (auto raw = trivial.GetRawPtr())
{
if (auto obj = dynamic_cast<IDescriptable*>(raw))
{
auto ref = lc->PtrToRef(Ptr<IDescriptable>(obj));
return BoxValue(ref);
}
}
}
return trivial;
}
Value RpcUnboxValueByvalInternal(const Value& serializable, IRpcLifecycle* lc, Dictionary<const DescriptableObject*, bool>& visited)
{
if (serializable.IsNull()) return serializable;
if (IsRpcObjectReferenceValue(serializable))
{
auto ref = GetRpcObjectReference(serializable);
auto obj = RpcUnboxByref(ref, lc);
return BoxValue(obj);
}
if (serializable.GetValueType() == Value::SharedPtr)
{
if (auto roDict = TryGetValueInterface<IValueReadonlyDictionary>(serializable))
{
auto key = static_cast<const DescriptableObject*>(serializable.GetRawPtr());
if (ContainsKey(visited, key)) CHECK_FAIL(L"Byval unboxing does not support cycles.");
visited.Add(key, true);
auto dict = IValueDictionary::Create();
auto keys = roDict->GetKeys();
for (vint i = 0; i < keys->GetCount(); i++)
{
auto dictKey = keys->Get(i);
dict->Set(
RpcUnboxValueByvalInternal(dictKey, lc, visited),
RpcUnboxValueByvalInternal(roDict->Get(dictKey), lc, visited)
);
}
visited.Remove(key);
return BoxValue(dict);
}
if (auto obsList = TryGetValueInterface<IValueObservableList>(serializable))
{
auto key = static_cast<const DescriptableObject*>(serializable.GetRawPtr());
if (ContainsKey(visited, key)) CHECK_FAIL(L"Byval unboxing does not support cycles.");
visited.Add(key, true);
auto list = IValueObservableList::Create();
for (vint i = 0; i < obsList->GetCount(); i++)
{
list->Add(RpcUnboxValueByvalInternal(obsList->Get(i), lc, visited));
}
visited.Remove(key);
return BoxValue(list);
}
if (auto array = TryGetValueInterface<IValueArray>(serializable))
{
auto key = static_cast<const DescriptableObject*>(serializable.GetRawPtr());
if (ContainsKey(visited, key)) CHECK_FAIL(L"Byval unboxing does not support cycles.");
visited.Add(key, true);
auto list = IValueArray::Create();
list->Resize(array->GetCount());
for (vint i = 0; i < array->GetCount(); i++)
{
list->Set(i, RpcUnboxValueByvalInternal(array->Get(i), lc, visited));
}
visited.Remove(key);
return BoxValue(list);
}
if (auto roList = TryGetValueInterface<IValueReadonlyList>(serializable))
{
auto key = static_cast<const DescriptableObject*>(serializable.GetRawPtr());
if (ContainsKey(visited, key)) CHECK_FAIL(L"Byval unboxing does not support cycles.");
visited.Add(key, true);
auto list = IValueList::Create();
for (vint i = 0; i < roList->GetCount(); i++)
{
list->Add(RpcUnboxValueByvalInternal(roList->Get(i), lc, visited));
}
visited.Remove(key);
return BoxValue(list);
}
}
return serializable;
}
}
void MergeRpcEventExceptionMap(RpcEventExceptionMap target, RpcEventExceptionMap source)
{
if (!source) return;
auto keys = source->GetKeys();
for (vint i = 0; i < keys->GetCount(); i++)
{
auto key = keys->Get(i);
target->Set(key, source->Get(key));
}
}
RpcObjectReference RpcBoxByref(Ptr<IDescriptable> trivial, IRpcLifecycle* lc)
{
if (!lc) CHECK_FAIL(L"IRpcLifecycle cannot be null.");
if (!trivial) return {};
return lc->PtrToRef(trivial);
}
Ptr<IDescriptable> RpcUnboxByref(RpcObjectReference serializable, IRpcLifecycle* lc)
{
if (!lc) CHECK_FAIL(L"IRpcLifecycle cannot be null.");
if (IsNullRpcObjectReference(serializable)) return nullptr;
return lc->RefToPtr(serializable);
}
Value RpcCopyByval(const Value& trivial, IRpcLifecycle* lc)
{
if (!lc) CHECK_FAIL(L"IRpcLifecycle cannot be null.");
if (trivial.IsNull()) return {};
Dictionary<const DescriptableObject*, bool> visited;
return RpcCopyValueByvalInternal(trivial, visited);
}
Value RpcBoxByval(Ptr<IDescriptable> trivial, IRpcLifecycle* lc)
{
if (!lc) CHECK_FAIL(L"IRpcLifecycle cannot be null.");
return RpcBoxByval(BoxValue(trivial), lc);
}
Value RpcBoxByval(const Value& trivial, IRpcLifecycle* lc)
{
if (!lc) CHECK_FAIL(L"IRpcLifecycle cannot be null.");
if (trivial.IsNull()) return {};
Dictionary<const DescriptableObject*, bool> visited;
return RpcBoxValueByvalInternal(trivial, lc, visited);
}
Ptr<IDescriptable> RpcUnboxByval(const Value& serializable, IRpcLifecycle* lc)
{
if (!lc) CHECK_FAIL(L"IRpcLifecycle cannot be null.");
if (serializable.IsNull()) return nullptr;
Dictionary<const DescriptableObject*, bool> visited;
auto trivial = RpcUnboxValueByvalInternal(serializable, lc, visited);
if (auto raw = trivial.GetRawPtr())
{
if (auto obj = dynamic_cast<IDescriptable*>(raw))
{
return Ptr<IDescriptable>(obj);
}
}
CHECK_FAIL(L"Interface value or null is expected.");
return nullptr;
}
void ReadMethodException(const Value& value)
{
if (value.GetValueType() == Value::BoxedValue)
{
if (auto boxed = value.GetBoxedValue().Cast<IValueType::TypedBox<RpcException>>())
{
throw Exception(boxed->value.message);
}
}
}
void ReadEventException(RpcEventExceptionMap exceptions)
{
if (!exceptions || exceptions->GetCount() == 0) return;
WString message;
auto keys = exceptions->GetKeys();
for (vint i = 0; i < keys->GetCount(); i++)
{
auto key = keys->Get(i);
auto exception = UnboxValue<RpcException>(exceptions->Get(key));
message += itow(UnboxValue<vint>(key)) + L":" + exception.message + L";";
}
throw Exception(message);
}
}
}
/***********************************************************************
.\RPC\WFLIBRARYRPCCONTROLLER.CPP
***********************************************************************/
namespace vl
{
namespace rpc_controller
{
using namespace collections;
/***********************************************************************
* RpcControllerDefault
***********************************************************************/
RpcControllerDefault::RpcControllerDefault()
{
}
RpcControllerDefault::~RpcControllerDefault()
{
}
void RpcControllerDefault::Register(Ptr<IRpcObjectOps> _objectCallback, Ptr<IRpcObjectEventOps> _eventCallback)
{
objectCallback = _objectCallback;
eventCallback = _eventCallback;
}
IRpcObjectOps* RpcControllerDefault::GetObjectOps()
{
return objectCallback.Obj();
}
IRpcObjectEventOps* RpcControllerDefault::GetObjectEventOps()
{
return eventCallback.Obj();
}
void RpcControllerDefault::Finalize()
{
}
template<typename TKey>
void RpcControllerDefault::SetSuppressedFlag(Dictionary<TKey, vint>& flags, const TKey& key, bool suppressed)
{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcControllerDefault::SetSuppressedFlag(collections::Dictionary<TKey, vint>&, const TKey&, bool)#"
auto index = flags.Keys().IndexOf(key);
if (suppressed)
{
if (index == -1)
{
flags.Add(key, 1);
}
else
{
flags.Set(key, flags.Values()[index] + 1);
}
}
else
{
CHECK_ERROR(index != -1, ERROR_MESSAGE_PREFIX L"Suppression counter is not set.");
auto count = flags.Values()[index] - 1;
CHECK_ERROR(count >= 0, ERROR_MESSAGE_PREFIX L"Suppression counter is negative.");
if (count == 0)
{
flags.Remove(key);
}
else
{
flags.Set(key, count);
}
}
#undef ERROR_MESSAGE_PREFIX
}
template<typename TKey>
bool RpcControllerDefault::GetSuppressedFlag(const Dictionary<TKey, vint>& flags, const TKey& key)
{
auto index = flags.Keys().IndexOf(key);
return index != -1 && flags.Values()[index] > 0;
}
void RpcControllerDefault::SetEventSuppressedFlag(RpcObjectReference ref, vint eventId, bool suppressed)
{
SetSuppressedFlag(eventSuppressedFlags, { ref,eventId }, suppressed);
}
bool RpcControllerDefault::GetEventSuppressedFlag(RpcObjectReference ref, vint eventId)
{
return GetSuppressedFlag(eventSuppressedFlags, { ref,eventId });
}
void RpcControllerDefault::SetItemChangedSuppressedFlag(RpcObjectReference ref, bool suppressed)
{
SetSuppressedFlag(itemChangedSuppressedFlags, ref, suppressed);
}
bool RpcControllerDefault::GetItemChangedSuppressedFlag(RpcObjectReference ref)
{
return GetSuppressedFlag(itemChangedSuppressedFlags, ref);
}
}
}
/***********************************************************************
.\RPC\WFLIBRARYRPCLIFECYCLE.CPP
***********************************************************************/
namespace vl
{
namespace rpc_controller
{
using namespace reflection;
using namespace reflection::description;
using namespace collections;
namespace
{
bool IsRpcWrapperObject(DescriptableObject* obj)
{
if (!obj) return false;
if (dynamic_cast<IRpcWrapperBase*>(obj)) return true;
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
if (auto typeDescriptor = obj->GetTypeDescriptor())
{
if (auto wrapperType = GetTypeDescriptor(WString::Unmanaged(L"system::IRpcWrapperBase")))
{
return typeDescriptor->CanConvertTo(wrapperType);
}
}
#endif
return false;
}
}
WString RpcLifecycleBase::InternalProperty_LocalObjectTracker = WString::Unmanaged(L"RpcLocalObjectTracker");
WString RpcLifecycleBase::InternalProperty_WrapperTracker = WString::Unmanaged(L"RpcWrapperTracker");
RpcLocalObjectTracker::RpcLocalObjectTracker(RpcLifecycleBase* lc, RpcObjectReference r)
: lifecycle(lc), ref(r)
{
}
RpcLocalObjectTracker::~RpcLocalObjectTracker()
{
if (lifecycle && lifecycle->IsTracked(ref.objectId))
{
lifecycle->RemoveLocalObject(ref, false);
}
}
void RpcLocalObjectTracker::Attach(RpcLifecycleBase* lc, RpcObjectReference r)
{
lifecycle = lc;
ref = r;
}
void RpcLocalObjectTracker::Detach()
{
lifecycle = nullptr;
}
RpcWrapperTracker::RpcWrapperTracker(RpcLifecycleBase* lc, RpcObjectReference r)
: lifecycle(lc), ref(r)
{
}
RpcWrapperTracker::~RpcWrapperTracker()
{
if (lifecycle)
{
lifecycle->UntrackWrapper(ref);
}
}
void RpcWrapperTracker::Detach()
{
lifecycle = nullptr;
}
/***********************************************************************
* RpcLifecycleBase (Constructor and Setup)
***********************************************************************/
RpcLifecycleBase::RpcLifecycleBase(vint _clientId)
: clientId(_clientId)
{
}
RpcLifecycleBase::~RpcLifecycleBase()
{
}
void RpcLifecycleBase::SetIdMap(const Dictionary<WString, vint>& _idMap)
{
CopyFrom(idMap, _idMap);
}
void RpcLifecycleBase::SetSerializer(Ptr<IRpcSerializer> _serializer)
{
serializer = _serializer;
}
IRpcSerializer* RpcLifecycleBase::GetSerializer()
{
return serializer.Obj();
}
void RpcLifecycleBase::RegisterWrapperFactory(UniversalWrapperFactory factory)
{
universalWrapperFactory = factory;
}
void RpcLifecycleBase::DisconnectWrappersForFinalize()
{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcLifecycleBase::DisconnectWrappersForFinalize()#"
for (auto [ref, properties] : wrapperProperties)
{
if (properties.root)
{
auto trackerObj = properties.root->GetInternalProperty(InternalProperty_WrapperTracker);
CHECK_ERROR(trackerObj, ERROR_MESSAGE_PREFIX L"Wrapper tracker missing.");
auto tracker = trackerObj.Cast<RpcWrapperTracker>();
CHECK_ERROR(tracker, ERROR_MESSAGE_PREFIX L"Invalid wrapper tracker type.");
tracker->Detach();
properties.root->SetInternalProperty(InternalProperty_WrapperTracker, nullptr);
}
if (properties.proxy)
{
properties.proxy->DisconnectFromLifecycle();
}
}
wrapperProperties.Clear();
#undef ERROR_MESSAGE_PREFIX
}
vint RpcLifecycleBase::DecideTypeId(IDescriptable* obj)const
{
if (dynamic_cast<IValueObservableList*>(obj)) return RpcTypeId_IValueObservableList;
if (dynamic_cast<IValueDictionary*>(obj)) return RpcTypeId_IValueDictionary;
if (dynamic_cast<IValueArray*>(obj)) return RpcTypeId_IValueArray;
if (dynamic_cast<IValueList*>(obj)) return RpcTypeId_IValueList;
if (dynamic_cast<IValueReadonlyList*>(obj)) return RpcTypeId_IValueReadonlyList;
if (dynamic_cast<IValueEnumerator*>(obj)) return RpcTypeId_IValueEnumerator;
if (dynamic_cast<IValueEnumerable*>(obj)) return RpcTypeId_IValueEnumerable;
return RpcTypeId_NotFound;
}
void RpcLifecycleBase::TrackLocalObject(RpcObjectReference ref, IDescriptable* obj)
{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcLifecycleBase::TrackLocalObject(RpcObjectReference, reflection::IDescriptable*)#"
auto index = localObjectProperties.Keys().IndexOf(ref.objectId);
CHECK_ERROR(index != -1, ERROR_MESSAGE_PREFIX L"Object not registered.");
auto props = localObjectProperties.Values().Get(index);
CHECK_ERROR(props->rawPtr == nullptr, ERROR_MESSAGE_PREFIX L"Object already tracked.");
props->rawPtr = obj;
if (auto observable = dynamic_cast<IValueObservableList*>(obj))
{
auto handler = observable->ItemChanged.Add([this, ref](vint index, vint oldCount, vint newCount)
{
if (this->GetController()->GetItemChangedSuppressedFlag(ref))
{
return;
}
auto listEventOps = Ptr(new RpcCallerListEventOps(
this->GetDispatcher()->BroadcastFromClient_ObjectEventOps(this->GetClientId()),
serializer.Obj()
));
listEventOps->OnItemChanged(ref, index, oldCount, newCount);
});
props->eventHandler = handler;
}
AttachLocalObjectEvents(ref, obj);
if (auto descriptable = dynamic_cast<DescriptableObject*>(obj))
{
Ptr<RpcLocalObjectTracker> tracker;
if (auto trackerObj = descriptable->GetInternalProperty(InternalProperty_LocalObjectTracker))
{
tracker = trackerObj.Cast<RpcLocalObjectTracker>();
CHECK_ERROR(tracker, ERROR_MESSAGE_PREFIX L"Invalid local object tracker type.");
if (tracker->GetClientId() != ref.clientId)
{
throw Exception(ERROR_MESSAGE_PREFIX L"Object already tracked by a different client.");
}
CHECK_ERROR(!tracker->IsTracked(), ERROR_MESSAGE_PREFIX L"Object already tracked.");
}
else
{
tracker = Ptr(new RpcLocalObjectTracker(this, ref));
descriptable->SetInternalProperty(InternalProperty_LocalObjectTracker, tracker);
}
tracker->Attach(this, ref);
}
#undef ERROR_MESSAGE_PREFIX
}
RpcObjectReference RpcLifecycleBase::CreateLocalObject(Ptr<IDescriptable> obj, RpcObjectReference ref)
{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcLifecycleBase::CreateLocalObject(Ptr<reflection::IDescriptable>, RpcObjectReference)#"
CHECK_ERROR(ref.clientId == clientId, ERROR_MESSAGE_PREFIX L"Ref is not local.");
CHECK_ERROR(!localObjectProperties.Keys().Contains(ref.objectId), ERROR_MESSAGE_PREFIX L"Object ID already registered.");
auto props = Ptr(new RpcLocalObjectProperties);
props->ref = ref;
props->ownedPtr = obj;
localObjectProperties.Set(ref.objectId, props);
TrackLocalObject(ref, obj.Obj());
if (nextObjectId < ref.objectId)
{
nextObjectId = ref.objectId;
}
return ref;
#undef ERROR_MESSAGE_PREFIX
}
void RpcLifecycleBase::UntrackLocalObject(RpcObjectReference ref, bool clearInternalProperty)
{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcLifecycleBase::UntrackLocalObject(RpcObjectReference, bool)#"
auto index = localObjectProperties.Keys().IndexOf(ref.objectId);
CHECK_ERROR(index != -1, ERROR_MESSAGE_PREFIX L"Object not registered.");
auto props = localObjectProperties.Values().Get(index);
if (props->eventHandler)
{
if (auto observable = dynamic_cast<IValueObservableList*>(props->rawPtr))
{
observable->ItemChanged.Remove(props->eventHandler);
}
props->eventHandler = nullptr;
}
auto rawPtr = props->rawPtr;
props->rawPtr = nullptr;
if (clearInternalProperty && rawPtr)
{
if (auto descriptable = dynamic_cast<DescriptableObject*>(rawPtr))
{
if (auto trackerObj = descriptable->GetInternalProperty(InternalProperty_LocalObjectTracker))
{
auto tracker = trackerObj.Cast<RpcLocalObjectTracker>();
CHECK_ERROR(tracker, ERROR_MESSAGE_PREFIX L"Invalid local object tracker type.");
tracker->Detach();
descriptable->SetInternalProperty(InternalProperty_LocalObjectTracker, nullptr);
}
}
}
props->ownedPtr = nullptr;
#undef ERROR_MESSAGE_PREFIX
}
void RpcLifecycleBase::RemoveLocalObject(RpcObjectReference ref, bool clearInternalProperty)
{
if (localObjectProperties.Keys().Contains(ref.objectId))
{
UntrackLocalObject(ref, clearInternalProperty);
localObjectProperties.Remove(ref.objectId);
}
}
bool RpcLifecycleBase::IsTracked(vint objectId)const
{
auto index = localObjectProperties.Keys().IndexOf(objectId);
return index != -1 && localObjectProperties.Values().Get(index)->rawPtr != nullptr;
}
void RpcLifecycleBase::TrackWrapper(DescriptableObject* root, IRpcWrapperBase* proxy, RpcObjectReference ref)
{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcLifecycleBase::TrackWrapper(reflection::DescriptableObject*, IRpcWrapperBase*, RpcObjectReference)#"
CHECK_ERROR(root != nullptr, ERROR_MESSAGE_PREFIX L"Wrapper does not implement DescriptableObject.");
CHECK_ERROR(proxy != nullptr, ERROR_MESSAGE_PREFIX L"Wrapper is null.");
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
root = root->SafeGetAggregationRoot();
#endif
CHECK_ERROR(root->GetInternalProperty(InternalProperty_WrapperTracker) == nullptr, ERROR_MESSAGE_PREFIX L"Wrapper already tracked.");
auto tracker = Ptr(new RpcWrapperTracker(this, ref));
root->SetInternalProperty(InternalProperty_WrapperTracker, tracker);
RpcWrapperProperties properties;
properties.root = root;
properties.proxy = proxy;
CHECK_ERROR(!wrapperProperties.Keys().Contains(ref), ERROR_MESSAGE_PREFIX L"Reference already tracked.");
wrapperProperties.Set(ref, properties);
#undef ERROR_MESSAGE_PREFIX
}
void RpcLifecycleBase::UntrackWrapper(RpcObjectReference ref)
{
wrapperProperties.Remove(ref);
}
bool RpcLifecycleBase::TryGetTrackedWrapperRef(DescriptableObject* obj, RpcObjectReference& ref)const
{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcLifecycleBase::TryGetTrackedWrapperRef(reflection::DescriptableObject*, RpcObjectReference&)const#"
auto wrapperRoot = obj;
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
if (wrapperRoot)
{
wrapperRoot = wrapperRoot->SafeGetAggregationRoot();
}
#endif
if (wrapperRoot)
{
if (auto trackerObj = wrapperRoot->GetInternalProperty(InternalProperty_WrapperTracker))
{
auto tracker = trackerObj.Cast<RpcWrapperTracker>();
CHECK_ERROR(tracker, ERROR_MESSAGE_PREFIX L"Invalid internal property type.");
CHECK_ERROR(tracker->GetLifecycle() == this, ERROR_MESSAGE_PREFIX L"Wrapper registered to a different lifecycle.");
ref = tracker->GetRef();
return true;
}
}
return false;
#undef ERROR_MESSAGE_PREFIX
}
IRpcWrapperBase* RpcLifecycleBase::GetTrackedWrapper(RpcObjectReference ref)const
{
if (auto index = wrapperProperties.Keys().IndexOf(ref); index != -1)
{
return wrapperProperties.Values()[index].proxy;
}
return nullptr;
}
Ptr<IDescriptable> RpcLifecycleBase::CreateCallerProxy(RpcObjectReference ref, IRpcSerializer* serializer)
{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcLifecycleBase::CreateCallerProxy(RpcObjectReference)#"
IRpcLifecycle* lc = this;
Ptr<IRpcWrapperBase> wrapper;
switch (ref.typeId)
{
case RpcTypeId_IValueEnumerable:
wrapper = Ptr(new RpcByrefEnumerable(lc, ref, serializer));
break;
case RpcTypeId_IValueEnumerator:
wrapper = Ptr(new RpcByrefEnumerator(lc, ref, serializer));
break;
case RpcTypeId_IValueArray:
wrapper = Ptr(new RpcByrefArray(lc, ref, serializer));
break;
case RpcTypeId_IValueReadonlyList:
wrapper = Ptr(new RpcByrefReadonlyList(lc, ref, serializer));
break;
case RpcTypeId_IValueList:
wrapper = Ptr(new RpcByrefList(lc, ref, serializer));
break;
case RpcTypeId_IValueObservableList:
wrapper = Ptr(new RpcByrefObservableList(lc, ref, serializer));
break;
case RpcTypeId_IValueDictionary:
wrapper = Ptr(new RpcByrefDictionary(lc, ref, serializer));
break;
default:
CHECK_ERROR(universalWrapperFactory, ERROR_MESSAGE_PREFIX L"No wrapper factory registered.");
wrapper = universalWrapperFactory(ref, this);
CHECK_ERROR(wrapper, ERROR_MESSAGE_PREFIX L"Wrapper factory returned null.");
break;
}
auto descriptable = dynamic_cast<IDescriptable*>(wrapper.Obj());
CHECK_ERROR(descriptable, ERROR_MESSAGE_PREFIX L"Wrapper does not implement IDescriptable.");
auto root = dynamic_cast<DescriptableObject*>(descriptable);
TrackWrapper(root, wrapper.Obj(), ref);
return Ptr(descriptable);
#undef ERROR_MESSAGE_PREFIX
}
/***********************************************************************
* RpcLifecycleBase (IRpcLifecycle)
***********************************************************************/
void RpcLifecycleBase::Finalize()
{
DisconnectWrappersForFinalize();
while (localObjectProperties.Count() > 0)
{
auto props = localObjectProperties.Values().Get(localObjectProperties.Count() - 1);
RemoveLocalObject(props->ref, true);
}
registeredLocalServices.Clear();
registeredRemoteServices.Clear();
controller.Finalize();
}
void RpcLifecycleBase::Initialize()
{
if (!initialized)
{
GetDispatcher()->Initialize();
initialized = true;
}
}
vint RpcLifecycleBase::GetClientId()
{
return clientId;
}
RpcControllerDefault* RpcLifecycleBase::GetController()
{
return &controller;
}
const RpcLocalServiceMap& RpcLifecycleBase::GetRegisteredLocalServices()
{
return registeredLocalServices;
}
void RpcLifecycleBase::LocalObjectHold(RpcObjectReference ref, vint remoteClientId)
{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcLifecycleBase::LocalObjectHold(RpcObjectReference, vint)#"
CHECK_ERROR(ref.clientId == clientId, ERROR_MESSAGE_PREFIX L"Ref is not local.");
auto index = localObjectProperties.Keys().IndexOf(ref.objectId);
CHECK_ERROR(index != -1, ERROR_MESSAGE_PREFIX L"Object not registered.");
auto props = localObjectProperties.Values().Get(index);
if (!props->interestedClients.Contains(remoteClientId))
{
props->interestedClients.Add(remoteClientId);
}
#undef ERROR_MESSAGE_PREFIX
}
void RpcLifecycleBase::LocalObjectUnhold(RpcObjectReference ref, vint remoteClientId)
{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcLifecycleBase::LocalObjectUnhold(RpcObjectReference, vint)#"
CHECK_ERROR(ref.clientId == clientId, ERROR_MESSAGE_PREFIX L"Ref is not local.");
auto index = localObjectProperties.Keys().IndexOf(ref.objectId);
CHECK_ERROR(index != -1, ERROR_MESSAGE_PREFIX L"Object not registered.");
auto props = localObjectProperties.Values().Get(index);
CHECK_ERROR(props->interestedClients.Contains(remoteClientId), ERROR_MESSAGE_PREFIX L"Client does not hold this object.");
props->interestedClients.Remove(remoteClientId);
if (props->interestedClients.Count() == 0)
{
RemoveLocalObject(ref, true);
}
#undef ERROR_MESSAGE_PREFIX
}
void RpcLifecycleBase::RegisterLocalService(vint typeId, Ptr<IDescriptable> service)
{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcLifecycleBase::RegisterLocalService(vint, Ptr<IDescriptable>)#"
CHECK_ERROR(service, ERROR_MESSAGE_PREFIX L"Service is required.");
if (initialized)
{
throw Exception(ERROR_MESSAGE_PREFIX L"RegisterLocalService cannot be called after Initialize.");
}
if (registeredLocalServices.Keys().Contains(typeId))
{
throw Exception(ERROR_MESSAGE_PREFIX L"Service is already registered.");
}
auto ref = CreateLocalObject(service, RpcObjectReference{ clientId, typeId, typeId });
LocalObjectHold(ref, clientId);
registeredLocalServices.Set(typeId, service);
GetDispatcher()->DeclareLocalService(ref);
#undef ERROR_MESSAGE_PREFIX
}
void RpcLifecycleBase::DeclareRemoteService(RpcObjectReference ref)
{
registeredRemoteServices.Set(ref.typeId, ref);
}
vint RpcLifecycleBase::GetTypeIdFromName(WString typeName)
{
auto typeIndex = idMap.Keys().IndexOf(typeName);
if (typeIndex == -1)
{
return RpcTypeId_NotFound;
}
return idMap.Values()[typeIndex];
}
Ptr<IDescriptable> RpcLifecycleBase::RequestService(WString typeName)
{
auto typeId = GetTypeIdFromName(typeName);
if (typeId == RpcTypeId_NotFound)
{
return nullptr;
}
if (auto index = registeredLocalServices.Keys().IndexOf(typeId); index != -1)
{
return registeredLocalServices.Values()[index];
}
if (auto index = registeredRemoteServices.Keys().IndexOf(typeId); index != -1)
{
return RefToPtr(registeredRemoteServices.Values()[index]);
}
return nullptr;
}
Ptr<IDescriptable> RpcLifecycleBase::RefToPtr(RpcObjectReference ref)
{
return RefToPtr(ref, serializer.Obj());
}
Ptr<IDescriptable> RpcLifecycleBase::RefToPtr(RpcObjectReference ref, IRpcSerializer* serializer)
{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcLifecycleBase::RefToPtr(RpcObjectReference)#"
if (ref.clientId == clientId)
{
auto index = localObjectProperties.Keys().IndexOf(ref.objectId);
CHECK_ERROR(index != -1, ERROR_MESSAGE_PREFIX L"Object not registered.");
auto props = localObjectProperties.Values().Get(index);
CHECK_ERROR(props->rawPtr != nullptr, ERROR_MESSAGE_PREFIX L"Object not tracked.");
return Ptr(props->rawPtr);
}
else
{
if (auto index = wrapperProperties.Keys().IndexOf(ref); index != -1)
{
auto proxy = wrapperProperties.Values()[index].proxy;
auto descriptable = dynamic_cast<IDescriptable*>(proxy);
CHECK_ERROR(descriptable, ERROR_MESSAGE_PREFIX L"Wrapper does not implement IDescriptable.");
return Ptr(descriptable);
}
return CreateCallerProxy(ref, serializer);
}
#undef ERROR_MESSAGE_PREFIX
}
RpcObjectReference RpcLifecycleBase::PtrToRef(Ptr<IDescriptable> obj)
{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcLifecycleBase::PtrToRef(Ptr<reflection::IDescriptable>)#"
CHECK_ERROR(obj, ERROR_MESSAGE_PREFIX L"A value is required.");
if (auto descObj = dynamic_cast<DescriptableObject*>(obj.Obj()))
{
RpcObjectReference wrapperRef;
if (TryGetTrackedWrapperRef(descObj, wrapperRef))
{
return wrapperRef;
}
if (IsRpcWrapperObject(descObj))
{
CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Wrapper tracker lookup unexpectedly failed.");
}
}
if (auto descObj = dynamic_cast<DescriptableObject*>(obj.Obj()))
{
if (auto trackerObj = descObj->GetInternalProperty(InternalProperty_LocalObjectTracker))
{
auto tracker = trackerObj.Cast<RpcLocalObjectTracker>();
CHECK_ERROR(tracker, ERROR_MESSAGE_PREFIX L"Invalid internal property type.");
if (tracker->GetClientId() != clientId)
{
throw Exception(ERROR_MESSAGE_PREFIX L"Object registered to a different lifecycle.");
}
if (tracker->IsTracked())
{
CHECK_ERROR(tracker->GetLifecycle() == this, ERROR_MESSAGE_PREFIX L"Object tracker registered to an invalid lifecycle instance.");
return tracker->GetRef();
}
}
}
auto typeId = DecideTypeId(obj.Obj());
CHECK_ERROR(typeId != RpcTypeId_NotFound, ERROR_MESSAGE_PREFIX L"DecideTypeId returned RpcTypeId_NotFound (unknown type).");
return CreateLocalObject(obj, RpcObjectReference{ clientId, ++nextObjectId, typeId });
#undef ERROR_MESSAGE_PREFIX
}
}
}
/***********************************************************************
.\RPC\WFLIBRARYRPCWRAPPERS.CPP
***********************************************************************/
namespace vl
{
using namespace collections;
namespace rpc_controller
{
using namespace reflection;
using namespace reflection::description;
namespace
{
#ifndef VCZH_WORKFLOW_RPC_OBJECT_REFERENCE_VALUE_HELPERS
#define VCZH_WORKFLOW_RPC_OBJECT_REFERENCE_VALUE_HELPERS
bool IsRpcObjectReferenceValue(const Value& value)
{
return value.GetValueType() == Value::BoxedValue && value.GetBoxedValue().Cast<IValueType::TypedBox<RpcObjectReference>>();
}
RpcObjectReference GetRpcObjectReference(const Value& value)
{
auto boxed = value.GetBoxedValue().Cast<IValueType::TypedBox<RpcObjectReference>>();
CHECK_ERROR(boxed, L"RpcObjectReference is expected.");
return boxed->value;
}
#endif
IRpcWrapperBase* CastRpcWrapperBase(IDescriptable* obj)
{
if (!obj) return nullptr;
if (auto wrapper = dynamic_cast<IRpcWrapperBase*>(obj)) return wrapper;
return obj->SafeAggregationCast<IRpcWrapperBase>();
}
template<typename TInterface>
TInterface* CastRpcInterface(IDescriptable* obj)
{
if (!obj) return nullptr;
if (auto proxy = dynamic_cast<TInterface*>(obj)) return proxy;
return obj->SafeAggregationCast<TInterface>();
}
template<typename TWrapper, typename TInterface>
Ptr<TInterface> CreateTrackedProxy(IRpcLifecycle* lc, RpcObjectReference ref, IRpcSerializer* serializer)
{
auto obj = [&]()
{
if (auto lifecycle = dynamic_cast<RpcLifecycleBase*>(lc))
{
return lifecycle->RefToPtr(ref, serializer);
}
return lc->RefToPtr(ref);
}();
CHECK_ERROR(obj, L"RPC proxy creation returned null.");
if (auto wrapper = Ptr(CastRpcWrapperBase(obj.Obj())))
{
auto proxy = Ptr(CastRpcInterface<TInterface>(obj.Obj()));
CHECK_ERROR(proxy, L"RPC proxy creation returned an unexpected type.");
return proxy;
}
return Ptr(new TWrapper(lc, ref, serializer));
}
void SetRemoteObjectHold(IRpcLifecycle* lc, RpcObjectReference ref, bool hold)
{
lc->GetDispatcher()->SendToClient_ObjectOps(ref.clientId)->ObjectHold(ref, lc->GetClientId(), hold);
}
Ptr<IRpcListOps> GetRemoteListOps(IRpcLifecycle* lc, RpcObjectReference ref, IRpcSerializer* serializer)
{
return Ptr(new RpcCallerListOps(lc->GetDispatcher()->SendToClient_ObjectOps(ref.clientId), serializer));
}
Value SerializeValue(IRpcSerializer* serializer, const Value& value)
{
return serializer ? serializer->Serialize(value) : value;
}
Value DeserializeValue(IRpcSerializer* serializer, const Value& value)
{
return serializer ? serializer->Deserialize(value) : value;
}
template<typename ...TArgs>
Ptr<IValueArray> CreateRpcArguments(TArgs&& ...args)
{
auto arguments = IValueArray::Create();
arguments->Resize(sizeof...(TArgs));
vint index = 0;
((arguments->Set(index++, std::forward<TArgs>(args))), ...);
return arguments;
}
Value ReadMethodResult(IRpcSerializer* serializer, const Value& value)
{
auto deserialized = DeserializeValue(serializer, value);
ReadMethodException(deserialized);
return deserialized;
}
Value InvokeListMethod(IRpcObjectOps* objectOps, IRpcSerializer* serializer, RpcObjectReference ref, vint methodId, Ptr<IValueArray> arguments)
{
auto result = objectOps->InvokeMethod(ref, methodId, arguments);
return ReadMethodResult(serializer, result);
}
bool IsRpcListMethodId(vint methodId)
{
switch (methodId)
{
case RpcMethodId_IValueEnumerable_CreateEnumerator:
case RpcMethodId_IValueEnumerator_Next:
case RpcMethodId_IValueEnumerator_GetCurrent:
case RpcMethodId_IValueReadonlyList_GetCount:
case RpcMethodId_IValueReadonlyList_Get:
case RpcMethodId_IValueList_Set:
case RpcMethodId_IValueList_Add:
case RpcMethodId_IValueList_Insert:
case RpcMethodId_IValueList_RemoveAt:
case RpcMethodId_IValueList_Clear:
case RpcMethodId_IValueReadonlyList_Contains:
case RpcMethodId_IValueReadonlyList_IndexOf:
case RpcMethodId_IValueReadonlyDictionary_GetCount:
case RpcMethodId_IValueReadonlyDictionary_Get:
case RpcMethodId_IValueDictionary_Set:
case RpcMethodId_IValueDictionary_Remove:
case RpcMethodId_IValueDictionary_Clear:
case RpcMethodId_IValueReadonlyDictionary_ContainsKey:
case RpcMethodId_IValueReadonlyDictionary_GetKeys:
case RpcMethodId_IValueReadonlyDictionary_GetValues:
case RpcMethodId_IValueArray_Resize:
return true;
default:
return false;
}
}
Value RpcBoxValueByref(const Value& trivial, IRpcLifecycle* lc)
{
if (!lc) CHECK_FAIL(L"IRpcLifecycle cannot be null.");
if (trivial.IsNull()) return trivial;
if (trivial.GetValueType() == Value::SharedPtr)
{
if (auto raw = trivial.GetRawPtr())
{
if (auto obj = dynamic_cast<IDescriptable*>(raw))
{
return BoxValue(RpcBoxByref(Ptr<IDescriptable>(obj), lc));
}
}
}
return trivial;
}
Value RpcUnboxValueByref(const Value& serializable, IRpcLifecycle* lc)
{
if (!lc) CHECK_FAIL(L"IRpcLifecycle cannot be null.");
if (serializable.IsNull()) return serializable;
if (IsRpcObjectReferenceValue(serializable))
{
auto ref = GetRpcObjectReference(serializable);
auto obj = RpcUnboxByref(ref, lc);
return BoxValue(obj);
}
return serializable;
}
}
/***********************************************************************
* RpcByrefEnumerator
***********************************************************************/
RpcByrefEnumerator::RpcByrefEnumerator(IRpcLifecycle* lc, RpcObjectReference enumeratorRef, IRpcSerializer* _serializer)
: lifecycle(lc)
, serializer(_serializer)
, ref(enumeratorRef)
{
if (!lifecycle) CHECK_FAIL(L"Invalid IRpcLifecycle.");
SetRemoteObjectHold(lifecycle, ref, true);
}
RpcByrefEnumerator::~RpcByrefEnumerator()
{
if (lifecycle) SetRemoteObjectHold(lifecycle, ref, false);
}
void RpcByrefEnumerator::DisconnectFromLifecycle()
{
lifecycle = nullptr;
}
Value RpcByrefEnumerator::GetCurrent()
{
return RpcUnboxValueByref(GetRemoteListOps(lifecycle, ref, serializer)->EnumGetCurrent(ref), lifecycle);
}
vint RpcByrefEnumerator::GetIndex()
{
return index;
}
bool RpcByrefEnumerator::Next()
{
if (GetRemoteListOps(lifecycle, ref, serializer)->EnumNext(ref))
{
index++;
return true;
}
return false;
}
RpcByrefEnumerable::RpcByrefEnumerable(IRpcLifecycle* lc, RpcObjectReference enumerableRef, IRpcSerializer* _serializer)
: lifecycle(lc)
, serializer(_serializer)
, ref(enumerableRef)
{
if (!lifecycle) CHECK_FAIL(L"Invalid IRpcLifecycle.");
SetRemoteObjectHold(lifecycle, ref, true);
}
RpcByrefEnumerable::~RpcByrefEnumerable()
{
if (lifecycle) SetRemoteObjectHold(lifecycle, ref, false);
}
void RpcByrefEnumerable::DisconnectFromLifecycle()
{
lifecycle = nullptr;
}
Ptr<IValueEnumerator> RpcByrefEnumerable::CreateEnumerator()
{
return CreateTrackedProxy<RpcByrefEnumerator, IValueEnumerator>(lifecycle, GetRemoteListOps(lifecycle, ref, serializer)->EnumCreate(ref), serializer);
}
/***********************************************************************
* RpcByrefReadonlyList
***********************************************************************/
RpcByrefReadonlyList::RpcByrefReadonlyList(IRpcLifecycle* lc, RpcObjectReference listRef, IRpcSerializer* _serializer)
: lifecycle(lc)
, serializer(_serializer)
, ref(listRef)
{
if (!lifecycle) CHECK_FAIL(L"Invalid IRpcLifecycle.");
SetRemoteObjectHold(lifecycle, ref, true);
}
RpcByrefReadonlyList::~RpcByrefReadonlyList()
{
if (lifecycle) SetRemoteObjectHold(lifecycle, ref, false);
}
void RpcByrefReadonlyList::DisconnectFromLifecycle()
{
lifecycle = nullptr;
}
Ptr<IValueEnumerator> RpcByrefReadonlyList::CreateEnumerator()
{
return CreateTrackedProxy<RpcByrefEnumerator, IValueEnumerator>(lifecycle, GetRemoteListOps(lifecycle, ref, serializer)->EnumCreate(ref), serializer);
}
vint RpcByrefReadonlyList::GetCount()
{
return GetRemoteListOps(lifecycle, ref, serializer)->ListGetCount(ref);
}
Value RpcByrefReadonlyList::Get(vint index)
{
return RpcUnboxValueByref(GetRemoteListOps(lifecycle, ref, serializer)->ListGet(ref, index), lifecycle);
}
bool RpcByrefReadonlyList::Contains(const Value& value)
{
return GetRemoteListOps(lifecycle, ref, serializer)->ListContains(ref, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle)));
}
vint RpcByrefReadonlyList::IndexOf(const Value& value)
{
return GetRemoteListOps(lifecycle, ref, serializer)->ListIndexOf(ref, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle)));
}
/***********************************************************************
* RpcByrefList
***********************************************************************/
RpcByrefList::RpcByrefList(IRpcLifecycle* lc, RpcObjectReference listRef, IRpcSerializer* _serializer)
: RpcByrefReadonlyList(lc, listRef, _serializer)
{
}
RpcByrefList::~RpcByrefList()
{
}
Ptr<IValueEnumerator> RpcByrefList::CreateEnumerator()
{
return RpcByrefReadonlyList::CreateEnumerator();
}
vint RpcByrefList::GetCount()
{
return RpcByrefReadonlyList::GetCount();
}
Value RpcByrefList::Get(vint index)
{
return RpcByrefReadonlyList::Get(index);
}
bool RpcByrefList::Contains(const Value& value)
{
return RpcByrefReadonlyList::Contains(value);
}
vint RpcByrefList::IndexOf(const Value& value)
{
return RpcByrefReadonlyList::IndexOf(value);
}
void RpcByrefList::Set(vint index, const Value& value)
{
GetRemoteListOps(lifecycle, ref, serializer)->ListSet(ref, index, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle)));
}
vint RpcByrefList::Add(const Value& value)
{
return GetRemoteListOps(lifecycle, ref, serializer)->ListAdd(ref, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle)));
}
vint RpcByrefList::Insert(vint index, const Value& value)
{
return GetRemoteListOps(lifecycle, ref, serializer)->ListInsert(ref, index, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle)));
}
bool RpcByrefList::Remove(const Value& value)
{
auto index = IndexOf(value);
return index == -1 ? false : GetRemoteListOps(lifecycle, ref, serializer)->ListRemoveAt(ref, index);
}
bool RpcByrefList::RemoveAt(vint index)
{
return GetRemoteListOps(lifecycle, ref, serializer)->ListRemoveAt(ref, index);
}
void RpcByrefList::Clear()
{
GetRemoteListOps(lifecycle, ref, serializer)->ListClear(ref);
}
/***********************************************************************
* RpcByrefArray
***********************************************************************/
RpcByrefArray::RpcByrefArray(IRpcLifecycle* lc, RpcObjectReference arrayRef, IRpcSerializer* _serializer)
: lifecycle(lc)
, serializer(_serializer)
, ref(arrayRef)
{
if (!lifecycle) CHECK_FAIL(L"Invalid IRpcLifecycle.");
SetRemoteObjectHold(lifecycle, ref, true);
}
RpcByrefArray::~RpcByrefArray()
{
if (lifecycle) SetRemoteObjectHold(lifecycle, ref, false);
}
void RpcByrefArray::DisconnectFromLifecycle()
{
lifecycle = nullptr;
}
Ptr<IValueEnumerator> RpcByrefArray::CreateEnumerator()
{
return CreateTrackedProxy<RpcByrefEnumerator, IValueEnumerator>(lifecycle, GetRemoteListOps(lifecycle, ref, serializer)->EnumCreate(ref), serializer);
}
vint RpcByrefArray::GetCount()
{
return GetRemoteListOps(lifecycle, ref, serializer)->ListGetCount(ref);
}
Value RpcByrefArray::Get(vint index)
{
return RpcUnboxValueByref(GetRemoteListOps(lifecycle, ref, serializer)->ListGet(ref, index), lifecycle);
}
bool RpcByrefArray::Contains(const Value& value)
{
return GetRemoteListOps(lifecycle, ref, serializer)->ListContains(ref, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle)));
}
vint RpcByrefArray::IndexOf(const Value& value)
{
return GetRemoteListOps(lifecycle, ref, serializer)->ListIndexOf(ref, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle)));
}
void RpcByrefArray::Set(vint index, const Value& value)
{
GetRemoteListOps(lifecycle, ref, serializer)->ListSet(ref, index, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle)));
}
void RpcByrefArray::Resize(vint size)
{
GetRemoteListOps(lifecycle, ref, serializer)->ArrayResize(ref, size);
}
/***********************************************************************
* RpcByrefObservableList
***********************************************************************/
RpcByrefObservableList::RpcByrefObservableList(IRpcLifecycle* lc, RpcObjectReference listRef, IRpcSerializer* _serializer)
: lifecycle(lc)
, serializer(_serializer)
, ref(listRef)
{
if (!lifecycle) CHECK_FAIL(L"Invalid IRpcLifecycle.");
SetRemoteObjectHold(lifecycle, ref, true);
}
RpcByrefObservableList::~RpcByrefObservableList()
{
if (lifecycle) SetRemoteObjectHold(lifecycle, ref, false);
}
void RpcByrefObservableList::DisconnectFromLifecycle()
{
lifecycle = nullptr;
}
Ptr<IValueEnumerator> RpcByrefObservableList::CreateEnumerator()
{
return CreateTrackedProxy<RpcByrefEnumerator, IValueEnumerator>(lifecycle, GetRemoteListOps(lifecycle, ref, serializer)->EnumCreate(ref), serializer);
}
vint RpcByrefObservableList::GetCount()
{
return GetRemoteListOps(lifecycle, ref, serializer)->ListGetCount(ref);
}
Value RpcByrefObservableList::Get(vint index)
{
return RpcUnboxValueByref(GetRemoteListOps(lifecycle, ref, serializer)->ListGet(ref, index), lifecycle);
}
bool RpcByrefObservableList::Contains(const Value& value)
{
return GetRemoteListOps(lifecycle, ref, serializer)->ListContains(ref, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle)));
}
vint RpcByrefObservableList::IndexOf(const Value& value)
{
return GetRemoteListOps(lifecycle, ref, serializer)->ListIndexOf(ref, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle)));
}
void RpcByrefObservableList::Set(vint index, const Value& value)
{
GetRemoteListOps(lifecycle, ref, serializer)->ListSet(ref, index, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle)));
}
vint RpcByrefObservableList::Add(const Value& value)
{
return GetRemoteListOps(lifecycle, ref, serializer)->ListAdd(ref, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle)));
}
vint RpcByrefObservableList::Insert(vint index, const Value& value)
{
return GetRemoteListOps(lifecycle, ref, serializer)->ListInsert(ref, index, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle)));
}
bool RpcByrefObservableList::Remove(const Value& value)
{
auto index = IndexOf(value);
return index == -1 ? false : GetRemoteListOps(lifecycle, ref, serializer)->ListRemoveAt(ref, index);
}
bool RpcByrefObservableList::RemoveAt(vint index)
{
return GetRemoteListOps(lifecycle, ref, serializer)->ListRemoveAt(ref, index);
}
void RpcByrefObservableList::Clear()
{
GetRemoteListOps(lifecycle, ref, serializer)->ListClear(ref);
}
/***********************************************************************
* RpcByrefDictionary
***********************************************************************/
RpcByrefDictionary::RpcByrefDictionary(IRpcLifecycle* lc, RpcObjectReference dictRef, IRpcSerializer* _serializer)
: lifecycle(lc)
, serializer(_serializer)
, ref(dictRef)
{
if (!lifecycle) CHECK_FAIL(L"Invalid IRpcLifecycle.");
SetRemoteObjectHold(lifecycle, ref, true);
}
RpcByrefDictionary::~RpcByrefDictionary()
{
if (lifecycle) SetRemoteObjectHold(lifecycle, ref, false);
}
void RpcByrefDictionary::DisconnectFromLifecycle()
{
lifecycle = nullptr;
}
Ptr<IValueReadonlyList> RpcByrefDictionary::GetKeys()
{
return CreateTrackedProxy<RpcByrefReadonlyList, IValueReadonlyList>(lifecycle, GetRemoteListOps(lifecycle, ref, serializer)->DictGetKeys(ref), serializer);
}
Ptr<IValueReadonlyList> RpcByrefDictionary::GetValues()
{
return CreateTrackedProxy<RpcByrefReadonlyList, IValueReadonlyList>(lifecycle, GetRemoteListOps(lifecycle, ref, serializer)->DictGetValues(ref), serializer);
}
vint RpcByrefDictionary::GetCount()
{
return GetRemoteListOps(lifecycle, ref, serializer)->DictGetCount(ref);
}
Value RpcByrefDictionary::Get(const Value& key)
{
auto serializedKey = SerializeValue(serializer, RpcBoxValueByref(key, lifecycle));
auto serializedValue = GetRemoteListOps(lifecycle, ref, serializer)->DictGet(ref, serializedKey);
return RpcUnboxValueByref(serializedValue, lifecycle);
}
void RpcByrefDictionary::Set(const Value& key, const Value& value)
{
auto serializedKey = SerializeValue(serializer, RpcBoxValueByref(key, lifecycle));
auto serializedValue = SerializeValue(serializer, RpcBoxValueByref(value, lifecycle));
GetRemoteListOps(lifecycle, ref, serializer)->DictSet(ref, serializedKey, serializedValue);
}
bool RpcByrefDictionary::Remove(const Value& key)
{
return GetRemoteListOps(lifecycle, ref, serializer)->DictRemove(ref, SerializeValue(serializer, RpcBoxValueByref(key, lifecycle)));
}
void RpcByrefDictionary::Clear()
{
GetRemoteListOps(lifecycle, ref, serializer)->DictClear(ref);
}
/***********************************************************************
* RpcCalleeListOps
***********************************************************************/
RpcCalleeListOps::RpcCalleeListOps(IRpcLifecycle* lc, IRpcSerializer* _serializer)
: lifecycle(lc)
, serializer(_serializer)
{
if (!lifecycle) CHECK_FAIL(L"Invalid IRpcLifecycle.");
}
RpcObjectReference RpcCalleeListOps::EnumCreate(RpcObjectReference ref)
{
auto obj = lifecycle->RefToPtr(ref);
Ptr<IValueEnumerator> enumerator;
if (auto xs = Ptr(obj.Obj()->SafeAggregationCast<IValueEnumerable>()))
{
enumerator = xs->CreateEnumerator();
}
else
{
throw Exception(L"RpcCalleeListOps::EnumCreate cannot find the target collection.");
}
return lifecycle->PtrToRef(enumerator);
}
bool RpcCalleeListOps::EnumNext(RpcObjectReference enumerator)
{
auto obj = lifecycle->RefToPtr(enumerator);
auto e = Ptr(obj.Obj()->SafeAggregationCast<IValueEnumerator>());
if (!e) throw Exception(L"RpcCalleeListOps::EnumNext cannot find the target enumerator.");
return e->Next();
}
Value RpcCalleeListOps::EnumGetCurrent(RpcObjectReference enumerator)
{
auto obj = lifecycle->RefToPtr(enumerator);
auto e = Ptr(obj.Obj()->SafeAggregationCast<IValueEnumerator>());
if (!e) throw Exception(L"RpcCalleeListOps::EnumGetCurrent cannot find the target enumerator.");
return SerializeValue(serializer, RpcBoxValueByref(e->GetCurrent(), lifecycle));
}
vint RpcCalleeListOps::ListGetCount(RpcObjectReference ref)
{
auto obj = lifecycle->RefToPtr(ref);
if (auto roList = Ptr(obj.Obj()->SafeAggregationCast<IValueReadonlyList>()))
return roList->GetCount();
throw Exception(L"RpcCalleeListOps::ListGetCount cannot find the target list.");
}
Value RpcCalleeListOps::ListGet(RpcObjectReference ref, vint index)
{
auto obj = lifecycle->RefToPtr(ref);
if (auto roList = Ptr(obj.Obj()->SafeAggregationCast<IValueReadonlyList>()))
return SerializeValue(serializer, RpcBoxValueByref(roList->Get(index), lifecycle));
throw Exception(L"RpcCalleeListOps::ListGet cannot find the target list.");
}
void RpcCalleeListOps::ListSet(RpcObjectReference ref, vint index, const Value& value)
{
auto trivial = RpcUnboxValueByref(DeserializeValue(serializer, value), lifecycle);
auto obj = lifecycle->RefToPtr(ref);
if (auto array = Ptr(obj.Obj()->SafeAggregationCast<IValueArray>()))
{
array->Set(index, trivial);
return;
}
if (auto list = Ptr(obj.Obj()->SafeAggregationCast<IValueList>()))
{
list->Set(index, trivial);
return;
}
throw Exception(L"RpcCalleeListOps::ListSet cannot find the target list.");
}
vint RpcCalleeListOps::ListAdd(RpcObjectReference ref, const Value& value)
{
auto trivial = RpcUnboxValueByref(DeserializeValue(serializer, value), lifecycle);
auto obj = lifecycle->RefToPtr(ref);
if (auto list = Ptr(obj.Obj()->SafeAggregationCast<IValueList>()))
return list->Add(trivial);
throw Exception(L"RpcCalleeListOps::ListAdd cannot find a writable list.");
}
vint RpcCalleeListOps::ListInsert(RpcObjectReference ref, vint index, const Value& value)
{
auto trivial = RpcUnboxValueByref(DeserializeValue(serializer, value), lifecycle);
auto obj = lifecycle->RefToPtr(ref);
if (auto list = Ptr(obj.Obj()->SafeAggregationCast<IValueList>()))
return list->Insert(index, trivial);
throw Exception(L"RpcCalleeListOps::ListInsert cannot find a writable list.");
}
bool RpcCalleeListOps::ListRemoveAt(RpcObjectReference ref, vint index)
{
auto obj = lifecycle->RefToPtr(ref);
if (auto list = Ptr(obj.Obj()->SafeAggregationCast<IValueList>()))
return list->RemoveAt(index);
throw Exception(L"RpcCalleeListOps::ListRemoveAt cannot find the target list.");
}
void RpcCalleeListOps::ListClear(RpcObjectReference ref)
{
auto obj = lifecycle->RefToPtr(ref);
if (auto list = Ptr(obj.Obj()->SafeAggregationCast<IValueList>()))
{
list->Clear();
return;
}
throw Exception(L"RpcCalleeListOps::ListClear cannot find the target list.");
}
bool RpcCalleeListOps::ListContains(RpcObjectReference ref, const Value& value)
{
auto trivial = RpcUnboxValueByref(DeserializeValue(serializer, value), lifecycle);
auto obj = lifecycle->RefToPtr(ref);
if (auto roList = Ptr(obj.Obj()->SafeAggregationCast<IValueReadonlyList>()))
return roList->Contains(trivial);
throw Exception(L"RpcCalleeListOps::ListContains cannot find the target list.");
}
vint RpcCalleeListOps::ListIndexOf(RpcObjectReference ref, const Value& value)
{
auto trivial = RpcUnboxValueByref(DeserializeValue(serializer, value), lifecycle);
auto obj = lifecycle->RefToPtr(ref);
if (auto roList = Ptr(obj.Obj()->SafeAggregationCast<IValueReadonlyList>()))
return roList->IndexOf(trivial);
throw Exception(L"RpcCalleeListOps::ListIndexOf cannot find the target list.");
}
void RpcCalleeListOps::ArrayResize(RpcObjectReference ref, vint size)
{
auto obj = lifecycle->RefToPtr(ref);
auto array = Ptr(obj.Obj()->SafeAggregationCast<IValueArray>());
if (!array) throw Exception(L"RpcCalleeListOps::ArrayResize cannot find the target array.");
array->Resize(size);
}
vint RpcCalleeListOps::DictGetCount(RpcObjectReference ref)
{
auto obj = lifecycle->RefToPtr(ref);
auto dict = Ptr(obj.Obj()->SafeAggregationCast<IValueReadonlyDictionary>());
if (!dict) throw Exception(L"RpcCalleeListOps::DictGetCount cannot find the target dictionary.");
return dict->GetCount();
}
Value RpcCalleeListOps::DictGet(RpcObjectReference ref, const Value& key)
{
auto obj = lifecycle->RefToPtr(ref);
auto dict = Ptr(obj.Obj()->SafeAggregationCast<IValueReadonlyDictionary>());
if (!dict) throw Exception(L"RpcCalleeListOps::DictGet cannot find the target dictionary.");
auto trivialKey = RpcUnboxValueByref(DeserializeValue(serializer, key), lifecycle);
return SerializeValue(serializer, RpcBoxValueByref(dict->Get(trivialKey), lifecycle));
}
void RpcCalleeListOps::DictSet(RpcObjectReference ref, const Value& key, const Value& value)
{
auto obj = lifecycle->RefToPtr(ref);
auto dict = Ptr(obj.Obj()->SafeAggregationCast<IValueDictionary>());
if (!dict) throw Exception(L"RpcCalleeListOps::DictSet cannot find the target dictionary.");
auto trivialKey = RpcUnboxValueByref(DeserializeValue(serializer, key), lifecycle);
auto trivialValue = RpcUnboxValueByref(DeserializeValue(serializer, value), lifecycle);
dict->Set(trivialKey, trivialValue);
}
bool RpcCalleeListOps::DictRemove(RpcObjectReference ref, const Value& key)
{
auto obj = lifecycle->RefToPtr(ref);
auto dict = Ptr(obj.Obj()->SafeAggregationCast<IValueDictionary>());
if (!dict) throw Exception(L"RpcCalleeListOps::DictRemove cannot find the target dictionary.");
return dict->Remove(RpcUnboxValueByref(DeserializeValue(serializer, key), lifecycle));
}
void RpcCalleeListOps::DictClear(RpcObjectReference ref)
{
auto obj = lifecycle->RefToPtr(ref);
auto dict = Ptr(obj.Obj()->SafeAggregationCast<IValueDictionary>());
if (!dict) throw Exception(L"RpcCalleeListOps::DictClear cannot find the target dictionary.");
dict->Clear();
}
bool RpcCalleeListOps::DictContainsKey(RpcObjectReference ref, const Value& key)
{
auto obj = lifecycle->RefToPtr(ref);
auto dict = Ptr(obj.Obj()->SafeAggregationCast<IValueReadonlyDictionary>());
if (!dict) throw Exception(L"RpcCalleeListOps::DictContainsKey cannot find the target dictionary.");
return dict->GetKeys()->Contains(RpcUnboxValueByref(DeserializeValue(serializer, key), lifecycle));
}
RpcObjectReference RpcCalleeListOps::DictGetKeys(RpcObjectReference ref)
{
auto obj = lifecycle->RefToPtr(ref);
auto dict = Ptr(obj.Obj()->SafeAggregationCast<IValueReadonlyDictionary>());
if (!dict) throw Exception(L"RpcCalleeListOps::DictGetKeys cannot find the target dictionary.");
return lifecycle->PtrToRef(dict->GetKeys());
}
RpcObjectReference RpcCalleeListOps::DictGetValues(RpcObjectReference ref)
{
auto obj = lifecycle->RefToPtr(ref);
auto dict = Ptr(obj.Obj()->SafeAggregationCast<IValueReadonlyDictionary>());
if (!dict) throw Exception(L"RpcCalleeListOps::DictGetValues cannot find the target dictionary.");
return lifecycle->PtrToRef(dict->GetValues());
}
/***********************************************************************
* RpcCalleeListEventOps
***********************************************************************/
RpcCalleeListEventOps::RpcCalleeListEventOps(IRpcLifecycle* lc, IRpcSerializer* _serializer)
: lifecycle(lc)
, serializer(_serializer)
{
if (!lifecycle) CHECK_FAIL(L"Invalid IRpcLifecycle.");
}
Value RpcCalleeListEventOps::OnItemChanged(RpcObjectReference ref, vint index, vint oldCount, vint newCount)
{
struct SuppressFlag
{
IRpcLifecycle* lifecycle;
RpcObjectReference ref;
SuppressFlag(IRpcLifecycle* _lifecycle, RpcObjectReference _ref)
: lifecycle(_lifecycle)
, ref(_ref)
{
lifecycle->GetController()->SetItemChangedSuppressedFlag(ref, true);
}
~SuppressFlag()
{
lifecycle->GetController()->SetItemChangedSuppressedFlag(ref, false);
}
};
auto obj = lifecycle->RefToPtr(ref);
auto observable = Ptr(obj.Obj()->SafeAggregationCast<IValueObservableList>());
CHECK_ERROR(observable, L"RpcCalleeListEventOps::OnItemChanged cannot find the target observable list.");
RpcEventExceptionMap exceptions;
{
SuppressFlag suppressFlag(lifecycle, ref);
try
{
observable->ItemChanged(index, oldCount, newCount);
}
catch (const Exception& ex)
{
exceptions = IValueDictionary::Create();
exceptions->Set(BoxValue(lifecycle->GetClientId()), BoxValue(RpcException{ ex.Message() }));
}
}
return SerializeValue(serializer, BoxValue(exceptions));
}
/***********************************************************************
* RpcCalleeObjectOpsForList
***********************************************************************/
RpcCalleeObjectOpsForList::RpcCalleeObjectOpsForList(Ptr<RpcCalleeListOps> _listOps, Ptr<IRpcObjectOps> _objectOps, IRpcSerializer* _serializer)
: listOps(_listOps)
, objectOps(_objectOps)
, serializer(_serializer)
{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcCalleeObjectOpsForList::RpcCalleeObjectOpsForList(...)#"
CHECK_ERROR(listOps && objectOps, ERROR_MESSAGE_PREFIX L"List ops and object ops are required.");
#undef ERROR_MESSAGE_PREFIX
}
Value RpcCalleeObjectOpsForList::InvokeMethod(RpcObjectReference ref, vint methodId, Ptr<IValueArray> arguments)
{
if (!IsRpcListMethodId(methodId))
{
return objectOps->InvokeMethod(ref, methodId, arguments);
}
try
{
switch (methodId)
{
case RpcMethodId_IValueEnumerable_CreateEnumerator:
return SerializeValue(serializer, BoxValue(listOps->EnumCreate(ref)));
case RpcMethodId_IValueEnumerator_Next:
return SerializeValue(serializer, BoxValue(listOps->EnumNext(ref)));
case RpcMethodId_IValueEnumerator_GetCurrent:
return listOps->EnumGetCurrent(ref);
case RpcMethodId_IValueReadonlyList_GetCount:
return SerializeValue(serializer, BoxValue(listOps->ListGetCount(ref)));
case RpcMethodId_IValueReadonlyList_Get:
return listOps->ListGet(ref, UnboxValue<vint>(DeserializeValue(serializer, arguments->Get(0))));
case RpcMethodId_IValueList_Set:
listOps->ListSet(ref, UnboxValue<vint>(DeserializeValue(serializer, arguments->Get(0))), arguments->Get(1));
return SerializeValue(serializer, Value());
case RpcMethodId_IValueList_Add:
return SerializeValue(serializer, BoxValue(listOps->ListAdd(ref, arguments->Get(0))));
case RpcMethodId_IValueList_Insert:
return SerializeValue(serializer, BoxValue(listOps->ListInsert(ref, UnboxValue<vint>(DeserializeValue(serializer, arguments->Get(0))), arguments->Get(1))));
case RpcMethodId_IValueList_RemoveAt:
return SerializeValue(serializer, BoxValue(listOps->ListRemoveAt(ref, UnboxValue<vint>(DeserializeValue(serializer, arguments->Get(0))))));
case RpcMethodId_IValueList_Clear:
listOps->ListClear(ref);
return SerializeValue(serializer, Value());
case RpcMethodId_IValueReadonlyList_Contains:
return SerializeValue(serializer, BoxValue(listOps->ListContains(ref, arguments->Get(0))));
case RpcMethodId_IValueReadonlyList_IndexOf:
return SerializeValue(serializer, BoxValue(listOps->ListIndexOf(ref, arguments->Get(0))));
case RpcMethodId_IValueReadonlyDictionary_GetCount:
return SerializeValue(serializer, BoxValue(listOps->DictGetCount(ref)));
case RpcMethodId_IValueReadonlyDictionary_Get:
return listOps->DictGet(ref, arguments->Get(0));
case RpcMethodId_IValueDictionary_Set:
listOps->DictSet(ref, arguments->Get(0), arguments->Get(1));
return SerializeValue(serializer, Value());
case RpcMethodId_IValueDictionary_Remove:
return SerializeValue(serializer, BoxValue(listOps->DictRemove(ref, arguments->Get(0))));
case RpcMethodId_IValueDictionary_Clear:
listOps->DictClear(ref);
return SerializeValue(serializer, Value());
case RpcMethodId_IValueReadonlyDictionary_ContainsKey:
return SerializeValue(serializer, BoxValue(listOps->DictContainsKey(ref, arguments->Get(0))));
case RpcMethodId_IValueReadonlyDictionary_GetKeys:
return SerializeValue(serializer, BoxValue(listOps->DictGetKeys(ref)));
case RpcMethodId_IValueReadonlyDictionary_GetValues:
return SerializeValue(serializer, BoxValue(listOps->DictGetValues(ref)));
case RpcMethodId_IValueArray_Resize:
listOps->ArrayResize(ref, UnboxValue<vint>(DeserializeValue(serializer, arguments->Get(0))));
return SerializeValue(serializer, Value());
}
}
catch (const Exception& ex)
{
return SerializeValue(serializer, BoxValue(RpcException{ ex.Message() }));
}
CHECK_FAIL(L"Unknown RPC list method id.");
return {};
}
void RpcCalleeObjectOpsForList::EndInvokeMethod(vint slot)
{
objectOps->EndInvokeMethod(slot);
}
void RpcCalleeObjectOpsForList::ObjectHold(RpcObjectReference ref, vint remoteClientId, bool hold)
{
objectOps->ObjectHold(ref, remoteClientId, hold);
}
/***********************************************************************
* RpcCalleeObjectEventOpsForList
***********************************************************************/
RpcCalleeObjectEventOpsForList::RpcCalleeObjectEventOpsForList(Ptr<RpcCalleeListEventOps> _listEventOps, Ptr<IRpcObjectEventOps> _objectEventOps, IRpcSerializer* _serializer)
: listEventOps(_listEventOps)
, objectEventOps(_objectEventOps)
, serializer(_serializer)
{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcCalleeObjectEventOpsForList::RpcCalleeObjectEventOpsForList(...)#"
CHECK_ERROR(listEventOps && objectEventOps, ERROR_MESSAGE_PREFIX L"List event ops and object event ops are required.");
#undef ERROR_MESSAGE_PREFIX
}
Value RpcCalleeObjectEventOpsForList::InvokeEvent(RpcObjectReference ref, vint eventId, Ptr<IValueArray> arguments)
{
if (eventId == RpcEventId_IValueObservableList_ItemChanged)
{
return listEventOps->OnItemChanged(
ref,
UnboxValue<vint>(DeserializeValue(serializer, arguments->Get(0))),
UnboxValue<vint>(DeserializeValue(serializer, arguments->Get(1))),
UnboxValue<vint>(DeserializeValue(serializer, arguments->Get(2)))
);
}
return objectEventOps->InvokeEvent(ref, eventId, arguments);
}
/***********************************************************************
* RpcCallerListOps
***********************************************************************/
RpcCallerListOps::RpcCallerListOps(IRpcObjectOps* _objectOps, IRpcSerializer* _serializer)
: objectOps(_objectOps)
, serializer(_serializer)
{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcCallerListOps::RpcCallerListOps(...)#"
CHECK_ERROR(objectOps, ERROR_MESSAGE_PREFIX L"Object ops are required.");
#undef ERROR_MESSAGE_PREFIX
}
RpcObjectReference RpcCallerListOps::EnumCreate(RpcObjectReference ref)
{
auto result = InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueEnumerable_CreateEnumerator, CreateRpcArguments());
return UnboxValue<RpcObjectReference>(result);
}
bool RpcCallerListOps::EnumNext(RpcObjectReference enumerator)
{
auto result = InvokeListMethod(objectOps, serializer, enumerator, RpcMethodId_IValueEnumerator_Next, CreateRpcArguments());
return UnboxValue<bool>(result);
}
Value RpcCallerListOps::EnumGetCurrent(RpcObjectReference enumerator)
{
return InvokeListMethod(objectOps, serializer, enumerator, RpcMethodId_IValueEnumerator_GetCurrent, CreateRpcArguments());
}
vint RpcCallerListOps::ListGetCount(RpcObjectReference ref)
{
auto result = InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueReadonlyList_GetCount, CreateRpcArguments());
return UnboxValue<vint>(result);
}
Value RpcCallerListOps::ListGet(RpcObjectReference ref, vint index)
{
return InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueReadonlyList_Get, CreateRpcArguments(SerializeValue(serializer, BoxValue(index))));
}
void RpcCallerListOps::ListSet(RpcObjectReference ref, vint index, const Value& value)
{
InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueList_Set, CreateRpcArguments(SerializeValue(serializer, BoxValue(index)), value));
}
vint RpcCallerListOps::ListAdd(RpcObjectReference ref, const Value& value)
{
auto result = InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueList_Add, CreateRpcArguments(value));
return UnboxValue<vint>(result);
}
vint RpcCallerListOps::ListInsert(RpcObjectReference ref, vint index, const Value& value)
{
auto result = InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueList_Insert, CreateRpcArguments(SerializeValue(serializer, BoxValue(index)), value));
return UnboxValue<vint>(result);
}
bool RpcCallerListOps::ListRemoveAt(RpcObjectReference ref, vint index)
{
auto result = InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueList_RemoveAt, CreateRpcArguments(SerializeValue(serializer, BoxValue(index))));
return UnboxValue<bool>(result);
}
void RpcCallerListOps::ListClear(RpcObjectReference ref)
{
InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueList_Clear, CreateRpcArguments());
}
bool RpcCallerListOps::ListContains(RpcObjectReference ref, const Value& value)
{
auto result = InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueReadonlyList_Contains, CreateRpcArguments(value));
return UnboxValue<bool>(result);
}
vint RpcCallerListOps::ListIndexOf(RpcObjectReference ref, const Value& value)
{
auto result = InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueReadonlyList_IndexOf, CreateRpcArguments(value));
return UnboxValue<vint>(result);
}
void RpcCallerListOps::ArrayResize(RpcObjectReference ref, vint size)
{
InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueArray_Resize, CreateRpcArguments(SerializeValue(serializer, BoxValue(size))));
}
vint RpcCallerListOps::DictGetCount(RpcObjectReference ref)
{
auto result = InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueReadonlyDictionary_GetCount, CreateRpcArguments());
return UnboxValue<vint>(result);
}
Value RpcCallerListOps::DictGet(RpcObjectReference ref, const Value& key)
{
return InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueReadonlyDictionary_Get, CreateRpcArguments(key));
}
void RpcCallerListOps::DictSet(RpcObjectReference ref, const Value& key, const Value& value)
{
InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueDictionary_Set, CreateRpcArguments(key, value));
}
bool RpcCallerListOps::DictRemove(RpcObjectReference ref, const Value& key)
{
auto result = InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueDictionary_Remove, CreateRpcArguments(key));
return UnboxValue<bool>(result);
}
void RpcCallerListOps::DictClear(RpcObjectReference ref)
{
InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueDictionary_Clear, CreateRpcArguments());
}
bool RpcCallerListOps::DictContainsKey(RpcObjectReference ref, const Value& key)
{
auto result = InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueReadonlyDictionary_ContainsKey, CreateRpcArguments(key));
return UnboxValue<bool>(result);
}
RpcObjectReference RpcCallerListOps::DictGetKeys(RpcObjectReference ref)
{
auto result = InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueReadonlyDictionary_GetKeys, CreateRpcArguments());
return UnboxValue<RpcObjectReference>(result);
}
RpcObjectReference RpcCallerListOps::DictGetValues(RpcObjectReference ref)
{
auto result = InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueReadonlyDictionary_GetValues, CreateRpcArguments());
return UnboxValue<RpcObjectReference>(result);
}
/***********************************************************************
* RpcCallerListEventOps
***********************************************************************/
RpcCallerListEventOps::RpcCallerListEventOps(IRpcObjectEventOps* _objectEventOps, IRpcSerializer* _serializer)
: objectEventOps(_objectEventOps)
, serializer(_serializer)
{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcCallerListEventOps::RpcCallerListEventOps(...)#"
CHECK_ERROR(objectEventOps, ERROR_MESSAGE_PREFIX L"Object event ops are required.");
#undef ERROR_MESSAGE_PREFIX
}
Value RpcCallerListEventOps::OnItemChanged(RpcObjectReference ref, vint index, vint oldCount, vint newCount)
{
auto arguments = CreateRpcArguments(
SerializeValue(serializer, BoxValue(index)),
SerializeValue(serializer, BoxValue(oldCount)),
SerializeValue(serializer, BoxValue(newCount))
);
auto result = objectEventOps->InvokeEvent(ref, RpcEventId_IValueObservableList_ItemChanged, arguments);
ReadEventException(UnboxValue<RpcEventExceptionMap>(DeserializeValue(serializer, result)));
return result;
}
}
}
/***********************************************************************
.\RPCJSON\WFLIBRARYRPCJSON.CPP
***********************************************************************/
namespace vl
{
namespace rpc_controller
{
using namespace collections;
using namespace glr::json;
using namespace reflection;
using namespace reflection::description;
namespace
{
Ptr<JsonLiteral> CreateJsonLiteral(JsonLiteralValue value)
{
auto node = Ptr(new JsonLiteral);
node->value = value;
return node;
}
Ptr<JsonString> CreateJsonString(const WString& value)
{
auto node = Ptr(new JsonString);
node->content.value = value;
return node;
}
Ptr<JsonNumber> CreateJsonNumber(const WString& value)
{
auto node = Ptr(new JsonNumber);
node->content.value = value;
return node;
}
Ptr<JsonArray> CreateJsonArray()
{
return Ptr(new JsonArray);
}
Ptr<JsonObject> CreateJsonObject()
{
return Ptr(new JsonObject);
}
Ptr<JsonObject> GetJsonObject(Ptr<JsonNode> node)
{
auto object = node.Cast<JsonObject>();
CHECK_ERROR(object, L"JSON object is expected.");
return object;
}
Ptr<JsonArray> GetJsonArray(Ptr<JsonNode> node)
{
auto array = node.Cast<JsonArray>();
CHECK_ERROR(array, L"JSON array is expected.");
return array;
}
void AddJsonObjectField(Ptr<JsonObject> object, const WString& name, Ptr<JsonNode> value)
{
auto field = Ptr(new JsonObjectField);
field->name.value = name;
field->value = value;
object->fields.Add(field);
}
void SetJsonObjectField(Ptr<JsonObject> object, const WString& name, Ptr<JsonNode> value)
{
for (auto field : object->fields)
{
if (field->name.value == name)
{
field->value = value;
return;
}
}
AddJsonObjectField(object, name, value);
}
Ptr<JsonNode> GetJsonObjectField(Ptr<JsonObject> object, const WString& name)
{
for (auto field : object->fields)
{
if (field->name.value == name)
{
return field->value;
}
}
auto message = L"JSON object field not found: " + name;
CHECK_FAIL(message.Buffer());
}
Ptr<JsonNode> FindJsonObjectField(Ptr<JsonObject> object, const WString& name)
{
for (auto field : object->fields)
{
if (field->name.value == name)
{
return field->value;
}
}
return nullptr;
}
WString GetJsonString(Ptr<JsonNode> node)
{
auto stringNode = node.Cast<JsonString>();
CHECK_ERROR(stringNode, L"JSON string is expected.");
return stringNode->content.value;
}
WString GetJsonNumber(Ptr<JsonNode> node)
{
auto numberNode = node.Cast<JsonNumber>();
CHECK_ERROR(numberNode, L"JSON number is expected.");
return numberNode->content.value;
}
vint GetJsonInt(Ptr<JsonNode> node)
{
return __vwsn::Parse<vint>(GetJsonNumber(node));
}
bool GetJsonBool(Ptr<JsonNode> node)
{
auto literal = node.Cast<JsonLiteral>();
CHECK_ERROR(literal, L"JSON boolean is expected.");
if (literal->value == JsonLiteralValue::True) return true;
if (literal->value == JsonLiteralValue::False) return false;
CHECK_FAIL(L"JSON boolean is expected.");
return false;
}
Ptr<JsonNumber> CreateJsonNumber(vint value)
{
return CreateJsonNumber(__vwsn::ToString(value));
}
Ptr<JsonLiteral> CreateJsonBool(bool value)
{
return CreateJsonLiteral(value ? JsonLiteralValue::True : JsonLiteralValue::False);
}
Ptr<JsonNode> CreateUnknownTuple(const WString& keyword, Ptr<JsonNode> value)
{
auto array = CreateJsonArray();
array->items.Add(CreateJsonString(keyword));
array->items.Add(value);
return Ptr<JsonNode>(array);
}
template<typename T>
bool TrySerializeNumberPrimitive(const Value& value, const WString& keyword, Ptr<JsonNode>& result)
{
auto primitive = __vwsn::UnboxWeak<Nullable<T>>(value);
if (primitive)
{
result = CreateUnknownTuple(keyword, CreateJsonNumber(__vwsn::ToString(primitive.Value())));
return true;
}
return false;
}
template<typename T>
bool TrySerializeStringPrimitive(const Value& value, const WString& keyword, Ptr<JsonNode>& result)
{
auto primitive = __vwsn::UnboxWeak<Nullable<T>>(value);
if (primitive)
{
result = CreateUnknownTuple(keyword, CreateJsonString(__vwsn::ToString(primitive.Value())));
return true;
}
return false;
}
Ptr<JsonNode> SerializeCollection(const WString& keyword, Ptr<IValueEnumerable> enumerable, const RpcJsonSerializeCallback& rpcjson_Serialize)
{
auto object = CreateJsonObject();
AddJsonObjectField(object, WString::Unmanaged(L"$"), CreateJsonString(keyword));
auto values = CreateJsonArray();
auto enumerator = enumerable->CreateEnumerator();
while (enumerator->Next())
{
values->items.Add(rpcjson_Serialize(enumerator->GetCurrent()));
}
AddJsonObjectField(object, WString::Unmanaged(L"values"), values);
return Ptr<JsonNode>(object);
}
Ptr<JsonNode> SerializeMap(Ptr<IValueReadonlyDictionary> dictionary, const RpcJsonSerializeCallback& rpcjson_Serialize)
{
auto object = CreateJsonObject();
AddJsonObjectField(object, WString::Unmanaged(L"$"), CreateJsonString(WString::Unmanaged(L"map")));
auto values = CreateJsonArray();
auto keys = dictionary->GetKeys();
for (vint i = 0; i < keys->GetCount(); i++)
{
auto key = keys->Get(i);
auto pair = CreateJsonArray();
pair->items.Add(rpcjson_Serialize(key));
pair->items.Add(rpcjson_Serialize(dictionary->Get(key)));
values->items.Add(pair);
}
AddJsonObjectField(object, WString::Unmanaged(L"values"), values);
return Ptr<JsonNode>(object);
}
Ptr<JsonNode> TrySerializeCollectionTypes(const Value& value, const RpcJsonSerializeCallback& rpcjson_Serialize)
{
if (auto observableList = __vwsn::UnboxWeak<Ptr<IValueObservableList>>(value))
{
return SerializeCollection(WString::Unmanaged(L"oblist"), observableList, rpcjson_Serialize);
}
if (auto dictionary = __vwsn::UnboxWeak<Ptr<IValueDictionary>>(value))
{
return SerializeMap(dictionary, rpcjson_Serialize);
}
if (auto readonlyDictionary = __vwsn::UnboxWeak<Ptr<IValueReadonlyDictionary>>(value))
{
return SerializeMap(readonlyDictionary, rpcjson_Serialize);
}
if (auto list = __vwsn::UnboxWeak<Ptr<IValueList>>(value))
{
return SerializeCollection(WString::Unmanaged(L"list"), list, rpcjson_Serialize);
}
if (auto readonlyList = __vwsn::UnboxWeak<Ptr<IValueReadonlyList>>(value))
{
return SerializeCollection(WString::Unmanaged(L"list"), readonlyList, rpcjson_Serialize);
}
if (auto enumerable = __vwsn::UnboxWeak<Ptr<IValueEnumerable>>(value))
{
return SerializeCollection(WString::Unmanaged(L"list"), enumerable, rpcjson_Serialize);
}
return nullptr;
}
Ptr<JsonNode> TrySerializeRpcTypes(const Value& value)
{
if (auto ref = __vwsn::UnboxWeak<Nullable<RpcObjectReference>>(value))
{
auto object = CreateJsonObject();
AddJsonObjectField(object, WString::Unmanaged(L"$"), CreateJsonString(WString::Unmanaged(L"system::RpcObjectReference")));
AddJsonObjectField(object, WString::Unmanaged(L"clientId"), CreateJsonNumber(__vwsn::ToString(ref.Value().clientId)));
AddJsonObjectField(object, WString::Unmanaged(L"objectId"), CreateJsonNumber(__vwsn::ToString(ref.Value().objectId)));
AddJsonObjectField(object, WString::Unmanaged(L"typeId"), CreateJsonNumber(__vwsn::ToString(ref.Value().typeId)));
return Ptr<JsonNode>(object);
}
if (auto exception = __vwsn::UnboxWeak<Nullable<RpcException>>(value))
{
auto object = CreateJsonObject();
AddJsonObjectField(object, WString::Unmanaged(L"$"), CreateJsonString(WString::Unmanaged(L"system::RpcException")));
AddJsonObjectField(object, WString::Unmanaged(L"message"), CreateJsonString(exception.Value().message));
return Ptr<JsonNode>(object);
}
return nullptr;
}
Value DeserializeList(Ptr<JsonObject> object, bool observable, const RpcJsonDeserializeCallback& rpcjson_Deserialize)
{
auto values = GetJsonObjectField(object, WString::Unmanaged(L"values")).Cast<JsonArray>();
CHECK_ERROR(values, L"JSON array is expected.");
if (observable)
{
auto result = IValueObservableList::Create();
for (auto item : values->items)
{
result->Add(rpcjson_Deserialize(item));
}
return BoxValue(result);
}
else
{
auto result = IValueList::Create();
for (auto item : values->items)
{
result->Add(rpcjson_Deserialize(item));
}
return BoxValue(result);
}
}
Value DeserializeMap(Ptr<JsonObject> object, const RpcJsonDeserializeCallback& rpcjson_Deserialize)
{
auto values = GetJsonObjectField(object, WString::Unmanaged(L"values")).Cast<JsonArray>();
CHECK_ERROR(values, L"JSON array is expected.");
auto result = IValueDictionary::Create();
for (auto item : values->items)
{
auto pair = item.Cast<JsonArray>();
CHECK_ERROR(pair, L"JSON array is expected.");
result->Set(rpcjson_Deserialize(pair->items[0]), rpcjson_Deserialize(pair->items[1]));
}
return BoxValue(result);
}
Value TryDeserializeRpcTypes(Ptr<JsonObject> object, const WString& keyword)
{
if (keyword == L"system::RpcObjectReference")
{
return BoxValue(RpcObjectReference{
__vwsn::Parse<vint>(GetJsonNumber(GetJsonObjectField(object, WString::Unmanaged(L"clientId")))),
__vwsn::Parse<vint>(GetJsonNumber(GetJsonObjectField(object, WString::Unmanaged(L"objectId")))),
__vwsn::Parse<vint>(GetJsonNumber(GetJsonObjectField(object, WString::Unmanaged(L"typeId")))),
});
}
if (keyword == L"system::RpcException")
{
return BoxValue(RpcException{
GetJsonString(GetJsonObjectField(object, WString::Unmanaged(L"message"))),
});
}
return {};
}
RpcObjectReference GetRpcObjectReferenceFromJson(Ptr<JsonNode> node)
{
auto object = GetJsonObject(node);
return {
GetJsonInt(GetJsonObjectField(object, WString::Unmanaged(L"clientId"))),
GetJsonInt(GetJsonObjectField(object, WString::Unmanaged(L"objectId"))),
GetJsonInt(GetJsonObjectField(object, WString::Unmanaged(L"typeId"))),
};
}
Ptr<JsonObject> CreateRpcObjectReferenceJson(RpcObjectReference ref)
{
auto object = CreateJsonObject();
AddJsonObjectField(object, WString::Unmanaged(L"clientId"), CreateJsonNumber(ref.clientId));
AddJsonObjectField(object, WString::Unmanaged(L"objectId"), CreateJsonNumber(ref.objectId));
AddJsonObjectField(object, WString::Unmanaged(L"typeId"), CreateJsonNumber(ref.typeId));
return object;
}
Ptr<JsonNode> ValueToJsonNode(const Value& value)
{
if (value.GetValueType() == Value::SharedPtr)
{
if (auto node = value.GetSharedPtr().Cast<JsonNode>())
{
return node;
}
}
CHECK_FAIL(L"RPC JSON value should be a Ptr<JsonNode>.");
return nullptr;
}
Ptr<JsonArray> ValueArrayToJsonArray(Ptr<IValueArray> arguments)
{
auto array = CreateJsonArray();
for (vint i = 0; i < arguments->GetCount(); i++)
{
array->items.Add(ValueToJsonNode(arguments->Get(i)));
}
return array;
}
Ptr<IValueArray> JsonArrayToValueArray(Ptr<JsonNode> node)
{
auto array = GetJsonArray(node);
auto arguments = IValueArray::Create();
arguments->Resize(array->items.Count());
for (vint i = 0; i < array->items.Count(); i++)
{
arguments->Set(i, BoxValue(array->items[i]));
}
return arguments;
}
Ptr<JsonObject> CreateRpcMessage(const WString& method, vint requestId, vint sourceClientId)
{
auto object = CreateJsonObject();
AddJsonObjectField(object, WString::Unmanaged(L"rpcMethod"), CreateJsonString(method));
AddJsonObjectField(object, WString::Unmanaged(L"rpcRequestId"), CreateJsonNumber(requestId));
AddJsonObjectField(object, WString::Unmanaged(L"sourceClientId"), CreateJsonNumber(sourceClientId));
return object;
}
vint ReadSourceClientId(Ptr<JsonObject> object)
{
return GetJsonInt(GetJsonObjectField(object, WString::Unmanaged(L"sourceClientId")));
}
vint ReadTargetClientId(Ptr<JsonObject> object)
{
return GetJsonInt(GetJsonObjectField(object, WString::Unmanaged(L"targetClientId")));
}
bool IsRpcMethodPrefix(const WString& rpcMethod, const WString& prefix)
{
return rpcMethod.Length() >= prefix.Length() && rpcMethod.Left(prefix.Length()) == prefix;
}
Ptr<JsonNode> MethodResultToJsonResponse(const Value& result)
{
if (result.GetValueType() == Value::SharedPtr)
{
if (auto byvalReturnValue = result.GetSharedPtr().Cast<RpcByvalReturnValue>())
{
auto object = CreateJsonObject();
AddJsonObjectField(object, WString::Unmanaged(L"value"), ValueToJsonNode(byvalReturnValue->value));
AddJsonObjectField(object, WString::Unmanaged(L"slot"), CreateJsonNumber(byvalReturnValue->slot));
return object;
}
}
return ValueToJsonNode(result);
}
Value JsonResponseToMethodResult(Ptr<JsonNode> node)
{
if (auto object = node.Cast<JsonObject>())
{
auto valueNode = FindJsonObjectField(object, WString::Unmanaged(L"value"));
auto slotNode = FindJsonObjectField(object, WString::Unmanaged(L"slot"));
if (valueNode && slotNode)
{
auto byvalReturnValue = Ptr(new RpcByvalReturnValue);
byvalReturnValue->value = BoxValue(valueNode);
byvalReturnValue->slot = GetJsonInt(slotNode);
return BoxValue(byvalReturnValue);
}
}
return BoxValue(node);
}
Ptr<JsonNode> SerializePredefinedValue(const Value& value)
{
RpcJsonSerializeCallback rpcjson_Serialize;
rpcjson_Serialize = Func<Ptr<JsonNode>(const Value&)>([&rpcjson_Serialize](const Value& item)
{
return JsonSerializePredefinedTypes(item, rpcjson_Serialize);
});
return JsonSerializePredefinedTypes(value, rpcjson_Serialize);
}
Value DeserializePredefinedValue(Ptr<JsonNode> node)
{
RpcJsonDeserializeCallback rpcjson_Deserialize;
rpcjson_Deserialize = Func<Value(Ptr<JsonNode>)>([&rpcjson_Deserialize](Ptr<JsonNode> item)
{
return JsonDeserializePredefinedTypes(BoxValue(item), rpcjson_Deserialize);
});
return JsonDeserializePredefinedTypes(BoxValue(node), rpcjson_Deserialize);
}
Ptr<JsonObject> CreatePlainRpcException(const RpcException& exception)
{
auto result = CreateJsonObject();
AddJsonObjectField(result, WString::Unmanaged(L"message"), CreateJsonString(exception.message));
return result;
}
RpcException ReadPlainRpcException(Ptr<JsonNode> node)
{
auto object = GetJsonObject(node);
return { GetJsonString(GetJsonObjectField(object, WString::Unmanaged(L"message"))) };
}
Ptr<JsonNode> CreateEventExceptionResponse(Ptr<JsonNode> serialized)
{
auto value = DeserializePredefinedValue(serialized);
if (value.IsNull())
{
return CreateJsonLiteral(JsonLiteralValue::Null);
}
auto exceptions = UnboxValue<RpcEventExceptionMap>(value);
auto result = CreateJsonArray();
auto keys = exceptions->GetKeys();
for (vint i = 0; i < keys->GetCount(); i++)
{
auto key = keys->Get(i);
auto resultPair = CreateJsonArray();
resultPair->items.Add(CreateJsonNumber(UnboxValue<vint>(key)));
resultPair->items.Add(CreatePlainRpcException(UnboxValue<RpcException>(exceptions->Get(key))));
result->items.Add(resultPair);
}
return result;
}
Ptr<JsonNode> CreateSerializedEventExceptionMap(Ptr<JsonNode> response)
{
if (auto literal = response.Cast<JsonLiteral>())
{
CHECK_ERROR(literal->value == JsonLiteralValue::Null, L"RPC event exception response should be null or an array.");
return SerializePredefinedValue({});
}
auto array = GetJsonArray(response);
auto exceptions = IValueDictionary::Create();
for (auto item : array->items)
{
auto pair = GetJsonArray(item);
CHECK_ERROR(pair->items.Count() == 2, L"RPC event exception response pair is expected.");
exceptions->Set(BoxValue(GetJsonInt(pair->items[0])), BoxValue(ReadPlainRpcException(pair->items[1])));
}
return SerializePredefinedValue(BoxValue(exceptions));
}
}
Ptr<JsonNode> JsonSerializePredefinedTypes(const Value& value, const RpcJsonSerializeCallback& rpcjson_Serialize)
{
if (value.IsNull())
{
return CreateJsonLiteral(JsonLiteralValue::Null);
}
if (auto primitive = __vwsn::UnboxWeak<Nullable<bool>>(value))
{
return CreateJsonLiteral(primitive.Value() ? JsonLiteralValue::True : JsonLiteralValue::False);
}
if (auto primitive = __vwsn::UnboxWeak<Nullable<WString>>(value))
{
return CreateJsonString(primitive.Value());
}
Ptr<JsonNode> result;
if (TrySerializeNumberPrimitive<vuint8_t>(value, WString::Unmanaged(L"UInt8"), result)) return result;
if (TrySerializeNumberPrimitive<vuint16_t>(value, WString::Unmanaged(L"UInt16"), result)) return result;
if (TrySerializeNumberPrimitive<vuint32_t>(value, WString::Unmanaged(L"UInt32"), result)) return result;
if (TrySerializeNumberPrimitive<vuint64_t>(value, WString::Unmanaged(L"UInt64"), result)) return result;
if (TrySerializeNumberPrimitive<vint8_t>(value, WString::Unmanaged(L"Int8"), result)) return result;
if (TrySerializeNumberPrimitive<vint16_t>(value, WString::Unmanaged(L"Int16"), result)) return result;
if (TrySerializeNumberPrimitive<vint32_t>(value, WString::Unmanaged(L"Int32"), result)) return result;
if (TrySerializeNumberPrimitive<vint64_t>(value, WString::Unmanaged(L"Int64"), result)) return result;
if (TrySerializeNumberPrimitive<float>(value, WString::Unmanaged(L"Single"), result)) return result;
if (TrySerializeNumberPrimitive<double>(value, WString::Unmanaged(L"Double"), result)) return result;
if (TrySerializeStringPrimitive<wchar_t>(value, WString::Unmanaged(L"Char"), result)) return result;
if (TrySerializeStringPrimitive<DateTime>(value, WString::Unmanaged(L"DateTime"), result)) return result;
if (TrySerializeStringPrimitive<Locale>(value, WString::Unmanaged(L"Locale"), result)) return result;
if (auto rpcType = TrySerializeRpcTypes(value))
{
return rpcType;
}
if (auto collection = TrySerializeCollectionTypes(value, rpcjson_Serialize))
{
return collection;
}
CHECK_FAIL(L"Unsupported RPC JSON serialization value.");
}
Value JsonDeserializePredefinedTypes(const Value& value, const RpcJsonDeserializeCallback& rpcjson_Deserialize)
{
if (value.IsNull())
{
return {};
}
auto node = UnboxValue<Ptr<JsonNode>>(value);
if (!node)
{
return {};
}
if (auto literal = node.Cast<JsonLiteral>())
{
switch (literal->value)
{
case JsonLiteralValue::Null:
return {};
case JsonLiteralValue::True:
return BoxValue(true);
case JsonLiteralValue::False:
return BoxValue(false);
default:
CHECK_FAIL(L"Unsupported JSON literal.");
}
}
if (auto stringNode = node.Cast<JsonString>())
{
return BoxValue(stringNode->content.value);
}
if (auto numberNode = node.Cast<JsonNumber>())
{
return BoxValue(numberNode->content.value);
}
if (auto array = node.Cast<JsonArray>())
{
if (array->items.Count() == 2)
{
if (auto keywordNode = array->items[0].Cast<JsonString>())
{
auto keyword = keywordNode->content.value;
auto item = array->items[1];
if (keyword == L"UInt8") return BoxValue(__vwsn::Parse<vuint8_t>(GetJsonNumber(item)));
if (keyword == L"UInt16") return BoxValue(__vwsn::Parse<vuint16_t>(GetJsonNumber(item)));
if (keyword == L"UInt32") return BoxValue(__vwsn::Parse<vuint32_t>(GetJsonNumber(item)));
if (keyword == L"UInt64") return BoxValue(__vwsn::Parse<vuint64_t>(GetJsonNumber(item)));
if (keyword == L"Int8") return BoxValue(__vwsn::Parse<vint8_t>(GetJsonNumber(item)));
if (keyword == L"Int16") return BoxValue(__vwsn::Parse<vint16_t>(GetJsonNumber(item)));
if (keyword == L"Int32") return BoxValue(__vwsn::Parse<vint32_t>(GetJsonNumber(item)));
if (keyword == L"Int64") return BoxValue(__vwsn::Parse<vint64_t>(GetJsonNumber(item)));
if (keyword == L"Single") return BoxValue(__vwsn::Parse<float>(GetJsonNumber(item)));
if (keyword == L"Double") return BoxValue(__vwsn::Parse<double>(GetJsonNumber(item)));
if (keyword == L"Char") return BoxValue(__vwsn::Parse<wchar_t>(GetJsonString(item)));
if (keyword == L"DateTime") return BoxValue(__vwsn::Parse<DateTime>(GetJsonString(item)));
if (keyword == L"Locale") return BoxValue(__vwsn::Parse<Locale>(GetJsonString(item)));
}
}
auto result = IValueList::Create();
for (auto item : array->items)
{
result->Add(rpcjson_Deserialize(item));
}
return BoxValue(result);
}
if (auto object = node.Cast<JsonObject>())
{
if (auto keywordNode = FindJsonObjectField(object, WString::Unmanaged(L"$")))
{
auto keyword = GetJsonString(keywordNode);
if (auto value = TryDeserializeRpcTypes(object, keyword); !value.IsNull()) return value;
if (keyword == L"list") return DeserializeList(object, false, rpcjson_Deserialize);
if (keyword == L"oblist") return DeserializeList(object, true, rpcjson_Deserialize);
if (keyword == L"map") return DeserializeMap(object, rpcjson_Deserialize);
CHECK_FAIL(L"Unknown RPC JSON object schema.");
}
auto result = IValueDictionary::Create();
for (auto field : object->fields)
{
result->Set(BoxValue(field->name.value), rpcjson_Deserialize(field->value));
}
return BoxValue(result);
}
CHECK_FAIL(L"Unsupported RPC JSON node.");
}
/***********************************************************************
* IRpcJsonMessageDispatcher
***********************************************************************/
Ptr<JsonNode> IRpcJsonMessageDispatcher::DefaultTranslate(
Ptr<JsonNode> message,
RequestType requestType,
IRpcObjectOps* objectOps,
IRpcObjectEventOps* objectEventOps,
IRpcDispatcher* dispatcher,
IRpcLifecycle* lifecycle
)
{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::IRpcJsonMessageDispatcher::DefaultTranslate(Ptr<JsonNode>, RequestType, IRpcObjectOps*, IRpcObjectEventOps*, IRpcDispatcher*, IRpcLifecycle*)#"
auto request = GetJsonObject(message);
auto rpcMethod = GetJsonString(GetJsonObjectField(request, WString::Unmanaged(L"rpcMethod")));
if (requestType == RequestType::Direct && IsRpcMethodPrefix(rpcMethod, WString::Unmanaged(L"Request:IObjectOps_")))
{
return RpcJsonObjectOps::Translate(message, objectOps, lifecycle);
}
else if (requestType == RequestType::Broadcast && IsRpcMethodPrefix(rpcMethod, WString::Unmanaged(L"Request:IObjectEventOps_")))
{
return RpcJsonObjectEventOps::Translate(message, objectEventOps, lifecycle);
}
else if (requestType == RequestType::BroadcastAndDrop && rpcMethod == WString::Unmanaged(L"Request:IRpcDispatcher_DeclareRemoteService"))
{
RpcJsonDispatcher::Translate(message, dispatcher, lifecycle);
return nullptr;
}
CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unknown JSON RPC method.");
return nullptr;
#undef ERROR_MESSAGE_PREFIX
}
/***********************************************************************
* RpcJsonObjectOps
***********************************************************************/
RpcJsonObjectOps::RpcJsonObjectOps(IRpcJsonMessageDispatcher* _dispatcher)
: dispatcher(_dispatcher)
{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonObjectOps::RpcJsonObjectOps(...)#"
CHECK_ERROR(dispatcher, ERROR_MESSAGE_PREFIX L"Dispatcher is required.");
#undef ERROR_MESSAGE_PREFIX
}
RpcJsonObjectOps::RpcJsonObjectOps(vint _sourceClientId, vint _targetClientId, IRpcJsonMessageDispatcher* _dispatcher)
: sourceClientId(_sourceClientId)
, targetClientId(_targetClientId)
, dispatcher(_dispatcher)
{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonObjectOps::RpcJsonObjectOps(...)#"
CHECK_ERROR(dispatcher, ERROR_MESSAGE_PREFIX L"Dispatcher is required.");
#undef ERROR_MESSAGE_PREFIX
}
RpcJsonObjectOps::~RpcJsonObjectOps()
{
}
Value RpcJsonObjectOps::InvokeMethod(RpcObjectReference ref, vint methodId, Ptr<IValueArray> arguments)
{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonObjectOps::InvokeMethod(RpcObjectReference, vint, Ptr<IValueArray>)#"
CHECK_ERROR(dispatcher, ERROR_MESSAGE_PREFIX L"Dispatcher is required.");
auto request = CreateRpcMessage(WString::Unmanaged(L"Request:IObjectOps_InvokeMethod"), dispatcher->AllocateRequestId(), sourceClientId);
AddJsonObjectField(request, WString::Unmanaged(L"targetClientId"), CreateJsonNumber(targetClientId == RpcClientId_Invalid ? ref.clientId : targetClientId));
AddJsonObjectField(request, WString::Unmanaged(L"ref"), CreateRpcObjectReferenceJson(ref));
AddJsonObjectField(request, WString::Unmanaged(L"methodId"), CreateJsonNumber(methodId));
AddJsonObjectField(request, WString::Unmanaged(L"arguments"), ValueArrayToJsonArray(arguments));
auto response = GetJsonObject(dispatcher->OnJsonRequest(request, IRpcJsonMessageDispatcher::RequestType::Direct));
CHECK_ERROR(GetJsonString(GetJsonObjectField(response, WString::Unmanaged(L"rpcMethod"))) == WString::Unmanaged(L"Response:IObjectOps_InvokeMethod"), ERROR_MESSAGE_PREFIX L"Unexpected response method.");
CHECK_ERROR(ReadRequestId(response) == ReadRequestId(request), ERROR_MESSAGE_PREFIX L"Unexpected response request id.");
return JsonResponseToMethodResult(GetJsonObjectField(response, WString::Unmanaged(L"response")));
#undef ERROR_MESSAGE_PREFIX
}
void RpcJsonObjectOps::EndInvokeMethod(vint slot)
{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonObjectOps::EndInvokeMethod(vint)#"
CHECK_ERROR(dispatcher, ERROR_MESSAGE_PREFIX L"Dispatcher is required.");
auto request = CreateRpcMessage(WString::Unmanaged(L"Request:IObjectOps_EndInvokeMethod"), dispatcher->AllocateRequestId(), sourceClientId);
AddJsonObjectField(request, WString::Unmanaged(L"targetClientId"), CreateJsonNumber(targetClientId));
AddJsonObjectField(request, WString::Unmanaged(L"slot"), CreateJsonNumber(slot));
auto response = GetJsonObject(dispatcher->OnJsonRequest(request, IRpcJsonMessageDispatcher::RequestType::Direct));
CHECK_ERROR(GetJsonString(GetJsonObjectField(response, WString::Unmanaged(L"rpcMethod"))) == WString::Unmanaged(L"Response:IObjectOps_EndInvokeMethod"), ERROR_MESSAGE_PREFIX L"Unexpected response method.");
CHECK_ERROR(ReadRequestId(response) == ReadRequestId(request), ERROR_MESSAGE_PREFIX L"Unexpected response request id.");
#undef ERROR_MESSAGE_PREFIX
}
void RpcJsonObjectOps::ObjectHold(RpcObjectReference ref, vint remoteClientId, bool hold)
{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonObjectOps::ObjectHold(RpcObjectReference, vint, bool)#"
CHECK_ERROR(dispatcher, ERROR_MESSAGE_PREFIX L"Dispatcher is required.");
auto request = CreateRpcMessage(WString::Unmanaged(L"Request:IObjectOps_ObjectHold"), dispatcher->AllocateRequestId(), sourceClientId == RpcClientId_Invalid ? remoteClientId : sourceClientId);
AddJsonObjectField(request, WString::Unmanaged(L"targetClientId"), CreateJsonNumber(targetClientId == RpcClientId_Invalid ? ref.clientId : targetClientId));
AddJsonObjectField(request, WString::Unmanaged(L"ref"), CreateRpcObjectReferenceJson(ref));
AddJsonObjectField(request, WString::Unmanaged(L"remoteClientId"), CreateJsonNumber(remoteClientId));
AddJsonObjectField(request, WString::Unmanaged(L"hold"), CreateJsonBool(hold));
auto response = GetJsonObject(dispatcher->OnJsonRequest(request, IRpcJsonMessageDispatcher::RequestType::Direct));
CHECK_ERROR(GetJsonString(GetJsonObjectField(response, WString::Unmanaged(L"rpcMethod"))) == WString::Unmanaged(L"Response:IObjectOps_ObjectHold"), ERROR_MESSAGE_PREFIX L"Unexpected response method.");
CHECK_ERROR(ReadRequestId(response) == ReadRequestId(request), ERROR_MESSAGE_PREFIX L"Unexpected response request id.");
#undef ERROR_MESSAGE_PREFIX
}
Ptr<JsonNode> RpcJsonObjectOps::Translate(Ptr<JsonNode> message, IRpcObjectOps* ops, IRpcLifecycle* lifecycle)
{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonObjectOps::Translate(Ptr<JsonNode>, IRpcObjectOps*)#"
(void)lifecycle;
CHECK_ERROR(ops, ERROR_MESSAGE_PREFIX L"Object ops is required.");
auto request = GetJsonObject(message);
auto rpcMethod = GetJsonString(GetJsonObjectField(request, WString::Unmanaged(L"rpcMethod")));
auto requestId = ReadRequestId(request);
auto sourceClientId = ReadSourceClientId(request);
auto targetClientId = ReadTargetClientId(request);
auto responseMethod =
rpcMethod == WString::Unmanaged(L"Request:IObjectOps_InvokeMethod") ? WString::Unmanaged(L"Response:IObjectOps_InvokeMethod") :
rpcMethod == WString::Unmanaged(L"Request:IObjectOps_EndInvokeMethod") ? WString::Unmanaged(L"Response:IObjectOps_EndInvokeMethod") :
rpcMethod == WString::Unmanaged(L"Request:IObjectOps_ObjectHold") ? WString::Unmanaged(L"Response:IObjectOps_ObjectHold") :
WString::Empty;
CHECK_ERROR(responseMethod != WString::Empty, ERROR_MESSAGE_PREFIX L"Unexpected RPC method.");
auto response = CreateRpcMessage(responseMethod, requestId, lifecycle ? lifecycle->GetClientId() : targetClientId);
AddJsonObjectField(response, WString::Unmanaged(L"targetClientId"), CreateJsonNumber(sourceClientId));
if (rpcMethod == WString::Unmanaged(L"Request:IObjectOps_InvokeMethod"))
{
auto result = ops->InvokeMethod(
GetRpcObjectReferenceFromJson(GetJsonObjectField(request, WString::Unmanaged(L"ref"))),
GetJsonInt(GetJsonObjectField(request, WString::Unmanaged(L"methodId"))),
JsonArrayToValueArray(GetJsonObjectField(request, WString::Unmanaged(L"arguments")))
);
AddJsonObjectField(response, WString::Unmanaged(L"response"), MethodResultToJsonResponse(result));
}
else if (rpcMethod == WString::Unmanaged(L"Request:IObjectOps_EndInvokeMethod"))
{
ops->EndInvokeMethod(GetJsonInt(GetJsonObjectField(request, WString::Unmanaged(L"slot"))));
}
else if (rpcMethod == WString::Unmanaged(L"Request:IObjectOps_ObjectHold"))
{
ops->ObjectHold(
GetRpcObjectReferenceFromJson(GetJsonObjectField(request, WString::Unmanaged(L"ref"))),
GetJsonInt(GetJsonObjectField(request, WString::Unmanaged(L"remoteClientId"))),
GetJsonBool(GetJsonObjectField(request, WString::Unmanaged(L"hold")))
);
}
else
{
CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unexpected RPC method.");
}
return response;
#undef ERROR_MESSAGE_PREFIX
}
/***********************************************************************
* RpcJsonObjectEventOps
***********************************************************************/
RpcJsonObjectEventOps::RpcJsonObjectEventOps(IRpcJsonMessageDispatcher* _dispatcher)
: dispatcher(_dispatcher)
{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonObjectEventOps::RpcJsonObjectEventOps(...)#"
CHECK_ERROR(dispatcher, ERROR_MESSAGE_PREFIX L"Dispatcher is required.");
#undef ERROR_MESSAGE_PREFIX
}
RpcJsonObjectEventOps::RpcJsonObjectEventOps(vint _sourceClientId, IRpcJsonMessageDispatcher* _dispatcher)
: sourceClientId(_sourceClientId)
, dispatcher(_dispatcher)
{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonObjectEventOps::RpcJsonObjectEventOps(...)#"
CHECK_ERROR(dispatcher, ERROR_MESSAGE_PREFIX L"Dispatcher is required.");
#undef ERROR_MESSAGE_PREFIX
}
RpcJsonObjectEventOps::~RpcJsonObjectEventOps()
{
}
Value RpcJsonObjectEventOps::InvokeEvent(RpcObjectReference ref, vint eventId, Ptr<IValueArray> arguments)
{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonObjectEventOps::InvokeEvent(RpcObjectReference, vint, Ptr<IValueArray>)#"
CHECK_ERROR(dispatcher, ERROR_MESSAGE_PREFIX L"Dispatcher is required.");
auto request = CreateRpcMessage(WString::Unmanaged(L"Request:IObjectEventOps_InvokeEvent"), dispatcher->AllocateRequestId(), sourceClientId);
AddJsonObjectField(request, WString::Unmanaged(L"ref"), CreateRpcObjectReferenceJson(ref));
AddJsonObjectField(request, WString::Unmanaged(L"eventId"), CreateJsonNumber(eventId));
AddJsonObjectField(request, WString::Unmanaged(L"arguments"), ValueArrayToJsonArray(arguments));
auto response = GetJsonObject(dispatcher->OnJsonRequest(request, IRpcJsonMessageDispatcher::RequestType::Broadcast));
CHECK_ERROR(GetJsonString(GetJsonObjectField(response, WString::Unmanaged(L"rpcMethod"))) == WString::Unmanaged(L"Response:Broadcast_Response"), ERROR_MESSAGE_PREFIX L"Unexpected response method.");
CHECK_ERROR(ReadRequestId(response) == ReadRequestId(request), ERROR_MESSAGE_PREFIX L"Unexpected response request id.");
return BoxValue(CreateSerializedEventExceptionMap(GetJsonObjectField(response, WString::Unmanaged(L"response"))));
#undef ERROR_MESSAGE_PREFIX
}
Ptr<JsonNode> RpcJsonObjectEventOps::Translate(Ptr<JsonNode> message, IRpcObjectEventOps* ops, IRpcLifecycle* lifecycle)
{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonObjectEventOps::Translate(Ptr<JsonNode>, IRpcObjectEventOps*)#"
CHECK_ERROR(ops, ERROR_MESSAGE_PREFIX L"Object event ops is required.");
auto request = GetJsonObject(message);
auto rpcMethod = GetJsonString(GetJsonObjectField(request, WString::Unmanaged(L"rpcMethod")));
CHECK_ERROR(rpcMethod == WString::Unmanaged(L"Request:IObjectEventOps_InvokeEvent"), ERROR_MESSAGE_PREFIX L"Unexpected RPC method.");
auto requestId = ReadRequestId(request);
auto sourceClientId = ReadSourceClientId(request);
auto response = CreateRpcMessage(WString::Unmanaged(L"Response:Broadcast_Response"), requestId, lifecycle ? lifecycle->GetClientId() : RpcClientId_Invalid);
AddJsonObjectField(response, WString::Unmanaged(L"targetClientId"), CreateJsonNumber(sourceClientId));
auto result = ops->InvokeEvent(
GetRpcObjectReferenceFromJson(GetJsonObjectField(request, WString::Unmanaged(L"ref"))),
GetJsonInt(GetJsonObjectField(request, WString::Unmanaged(L"eventId"))),
JsonArrayToValueArray(GetJsonObjectField(request, WString::Unmanaged(L"arguments")))
);
AddJsonObjectField(response, WString::Unmanaged(L"response"), CreateEventExceptionResponse(ValueToJsonNode(result)));
return response;
#undef ERROR_MESSAGE_PREFIX
}
/***********************************************************************
* RpcJsonDispatcher
***********************************************************************/
RpcJsonDispatcher::RpcJsonDispatcher(vint _sourceClientId, IRpcJsonMessageDispatcher* _dispatcher)
: sourceClientId(_sourceClientId)
, dispatcher(_dispatcher)
{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonDispatcher::RpcJsonDispatcher(vint, IRpcJsonMessageDispatcher*)#"
CHECK_ERROR(sourceClientId != RpcClientId_Invalid, ERROR_MESSAGE_PREFIX L"Source client id is required.");
CHECK_ERROR(dispatcher, ERROR_MESSAGE_PREFIX L"Dispatcher is required.");
#undef ERROR_MESSAGE_PREFIX
}
void RpcJsonDispatcher::Finalize()
{
}
void RpcJsonDispatcher::Initialize()
{
}
void RpcJsonDispatcher::DeclareLocalService(RpcObjectReference ref)
{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonDispatcher::DeclareLocalService(RpcObjectReference)#"
CHECK_ERROR(dispatcher, ERROR_MESSAGE_PREFIX L"Dispatcher is required.");
CHECK_ERROR(ref.clientId == sourceClientId, ERROR_MESSAGE_PREFIX L"Client id does not match this dispatcher.");
auto request = CreateRpcMessage(WString::Unmanaged(L"Request:IRpcDispatcher_DeclareRemoteService"), dispatcher->AllocateRequestId(), sourceClientId);
AddJsonObjectField(request, WString::Unmanaged(L"ref"), CreateRpcObjectReferenceJson(ref));
auto response = dispatcher->OnJsonRequest(request, IRpcJsonMessageDispatcher::RequestType::BroadcastAndDrop);
CHECK_ERROR(!response, ERROR_MESSAGE_PREFIX L"DeclareLocalService should not receive a response.");
#undef ERROR_MESSAGE_PREFIX
}
IRpcObjectEventOps* RpcJsonDispatcher::BroadcastFromClient_ObjectEventOps(vint selfClientId)
{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonDispatcher::BroadcastFromClient_ObjectEventOps(vint)#"
CHECK_ERROR(selfClientId == sourceClientId, ERROR_MESSAGE_PREFIX L"Client id does not match this dispatcher.");
if (!objectEventOps)
{
objectEventOps = Ptr(new RpcJsonObjectEventOps(sourceClientId, dispatcher));
}
return objectEventOps.Obj();
#undef ERROR_MESSAGE_PREFIX
}
IRpcObjectOps* RpcJsonDispatcher::SendToClient_ObjectOps(vint targetClientId)
{
if (auto index = objectOps.Keys().IndexOf(targetClientId); index != -1)
{
return objectOps.Values()[index].Obj();
}
auto ops = Ptr(new RpcJsonObjectOps(sourceClientId, targetClientId, dispatcher));
objectOps.Set(targetClientId, ops);
return ops.Obj();
}
Ptr<JsonNode> RpcJsonDispatcher::Translate(Ptr<JsonNode> message, IRpcDispatcher* dispatcher, IRpcLifecycle* lifecycle)
{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonDispatcher::Translate(Ptr<JsonNode>, IRpcDispatcher*, IRpcLifecycle*)#"
(void)dispatcher;
CHECK_ERROR(lifecycle, ERROR_MESSAGE_PREFIX L"Lifecycle is required.");
auto request = GetJsonObject(message);
auto rpcMethod = GetJsonString(GetJsonObjectField(request, WString::Unmanaged(L"rpcMethod")));
CHECK_ERROR(rpcMethod == WString::Unmanaged(L"Request:IRpcDispatcher_DeclareRemoteService"), ERROR_MESSAGE_PREFIX L"Unexpected RPC method.");
auto sourceClientId = ReadSourceClientId(request);
auto ref = GetRpcObjectReferenceFromJson(GetJsonObjectField(request, WString::Unmanaged(L"ref")));
CHECK_ERROR(ref.clientId == sourceClientId, ERROR_MESSAGE_PREFIX L"Client id does not match the message source.");
lifecycle->DeclareRemoteService(ref);
return nullptr;
#undef ERROR_MESSAGE_PREFIX
}
/***********************************************************************
* RpcJsonLifecycle
***********************************************************************/
RpcJsonLifecycle::RpcJsonLifecycle(vint _clientId, RpcJsonDispatcher* _dispatcher)
: RpcLifecycleBase(_clientId)
, dispatcher(_dispatcher)
{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonLifecycle::RpcJsonLifecycle(vint, RpcJsonDispatcher*)#"
CHECK_ERROR(dispatcher, ERROR_MESSAGE_PREFIX L"Dispatcher is required.");
#undef ERROR_MESSAGE_PREFIX
}
void RpcJsonLifecycle::Register(
Ptr<IRpcSerializer> _serializer,
Ptr<IRpcObjectOps> _objectOps,
Ptr<IRpcObjectEventOps> _objectEventOps,
Func<vint(IDescriptable*)> _getTypeId,
Func<void(RpcObjectReference, IDescriptable*)> _eventAttacher
)
{
serializer = _serializer;
getTypeId = _getTypeId;
eventAttacher = _eventAttacher;
listOps = Ptr(new RpcCalleeListOps(this, serializer.Obj()));
listEventOps = Ptr(new RpcCalleeListEventOps(this, serializer.Obj()));
objectOpsForList = Ptr(new RpcCalleeObjectOpsForList(listOps, _objectOps, serializer.Obj()));
objectEventOpsForList = Ptr(new RpcCalleeObjectEventOpsForList(listEventOps, _objectEventOps, serializer.Obj()));
GetController()->Register(objectOpsForList, objectEventOpsForList);
}
vint RpcJsonLifecycle::DecideTypeId(IDescriptable* obj)const
{
auto result = RpcLifecycleBase::DecideTypeId(obj);
if (result != RpcTypeId_NotFound) return result;
return getTypeId ? getTypeId(obj) : RpcTypeId_NotFound;
}
IRpcSerializer* RpcJsonLifecycle::GetSerializer()
{
return serializer.Obj();
}
IRpcDispatcher* RpcJsonLifecycle::GetDispatcher()
{
return dispatcher;
}
void RpcJsonLifecycle::AttachLocalObjectEvents(RpcObjectReference ref, IDescriptable* obj)
{
if (eventAttacher)
{
eventAttacher(ref, obj);
}
}
/***********************************************************************
* Request Id
***********************************************************************/
vint ReadRequestId(Ptr<JsonNode> message)
{
return GetJsonInt(GetJsonObjectField(GetJsonObject(message), WString::Unmanaged(L"rpcRequestId")));
}
void WriteRequestId(Ptr<JsonNode> message, vint requestId)
{
SetJsonObjectField(GetJsonObject(message), WString::Unmanaged(L"rpcRequestId"), CreateJsonNumber(requestId));
}
}
}
/***********************************************************************
.\RPCJSON\WFLIBRARYRPCJSONDISPATCHERCLIENT.CPP
***********************************************************************/
#include <cwchar>
namespace vl::rpc_controller::channeling
{
using namespace vl;
using namespace vl::collections;
using namespace vl::glr::json;
using namespace vl::inter_process;
using namespace vl::reflection;
using namespace vl::reflection::description;
using namespace vl::rpc_controller;
namespace
{
Ptr<JsonString> CreateJsonString(const WString& value)
{
auto node = Ptr(new JsonString);
node->content.value = value;
return node;
}
Ptr<JsonNumber> CreateJsonNumber(vint value)
{
auto node = Ptr(new JsonNumber);
node->content.value = itow(value);
return node;
}
Ptr<JsonObject> CreateJsonObject()
{
return Ptr(new JsonObject);
}
Ptr<JsonObject> GetJsonObject(Ptr<JsonNode> node)
{
auto object = node.Cast<JsonObject>();
CHECK_ERROR(object, L"RpcJsonDispatcherClient expects a JSON object.");
return object;
}
void AddJsonObjectField(Ptr<JsonObject> object, const WString& name, Ptr<JsonNode> value)
{
auto field = Ptr(new JsonObjectField);
field->name.value = name;
field->value = value;
object->fields.Add(field);
}
void SetJsonObjectField(Ptr<JsonObject> object, const WString& name, Ptr<JsonNode> value)
{
for (auto field : object->fields)
{
if (field->name.value == name)
{
field->value = value;
return;
}
}
AddJsonObjectField(object, name, value);
}
Ptr<JsonNode> FindJsonObjectField(Ptr<JsonObject> object, const WString& name)
{
for (auto field : object->fields)
{
if (field->name.value == name)
{
return field->value;
}
}
return nullptr;
}
Ptr<JsonNode> GetJsonObjectField(Ptr<JsonObject> object, const WString& name)
{
auto field = FindJsonObjectField(object, name);
CHECK_ERROR(field, L"RpcJsonDispatcherClient expects a JSON object field.");
return field;
}
WString GetJsonString(Ptr<JsonNode> node)
{
auto stringNode = node.Cast<JsonString>();
CHECK_ERROR(stringNode, L"RpcJsonDispatcherClient expects a JSON string.");
return stringNode->content.value;
}
vint GetJsonInt(Ptr<JsonNode> node)
{
auto numberNode = node.Cast<JsonNumber>();
CHECK_ERROR(numberNode, L"RpcJsonDispatcherClient expects a JSON number.");
return wtoi(numberNode->content.value);
}
bool StartsWith(const WString& value, const wchar_t* prefix)
{
auto prefixLength = (vint)wcslen(prefix);
return value.Length() >= prefixLength && wcsncmp(value.Buffer(), prefix, prefixLength) == 0;
}
WString TryReadRpcMethod(Ptr<JsonNode> message)
{
if (auto object = message.Cast<JsonObject>())
{
if (auto field = FindJsonObjectField(object, WString::Unmanaged(L"rpcMethod")))
{
if (auto stringNode = field.Cast<JsonString>())
{
return stringNode->content.value;
}
}
}
return WString::Empty;
}
bool IsRpcRequest(const WString& rpcMethod)
{
return StartsWith(rpcMethod, L"Request:");
}
bool IsRpcResponse(const WString& rpcMethod)
{
return StartsWith(rpcMethod, L"Response:");
}
bool IsDeclareRemoteServiceRequest(const WString& rpcMethod)
{
return rpcMethod == WString::Unmanaged(L"Request:IRpcDispatcher_DeclareRemoteService");
}
IRpcJsonMessageDispatcher::RequestType GetRequestType(const WString& rpcMethod)
{
if (StartsWith(rpcMethod, L"Request:IObjectOps_"))
{
return IRpcJsonMessageDispatcher::RequestType::Direct;
}
if (StartsWith(rpcMethod, L"Request:IObjectEventOps_"))
{
return IRpcJsonMessageDispatcher::RequestType::Broadcast;
}
if (IsDeclareRemoteServiceRequest(rpcMethod))
{
return IRpcJsonMessageDispatcher::RequestType::BroadcastAndDrop;
}
CHECK_FAIL(L"RpcJsonDispatcherClient received an unknown request method.");
return IRpcJsonMessageDispatcher::RequestType::Direct;
}
vint ReadRequestId(Ptr<JsonNode> message)
{
return GetJsonInt(GetJsonObjectField(GetJsonObject(message), WString::Unmanaged(L"rpcRequestId")));
}
vint ReadTargetClientId(Ptr<JsonNode> message)
{
return GetJsonInt(GetJsonObjectField(GetJsonObject(message), WString::Unmanaged(L"targetClientId")));
}
vint ReadDeclaredServiceTypeId(Ptr<JsonNode> message)
{
auto ref = GetJsonObject(GetJsonObjectField(GetJsonObject(message), WString::Unmanaged(L"ref")));
return GetJsonInt(GetJsonObjectField(ref, WString::Unmanaged(L"typeId")));
}
Ptr<JsonObject> CreateLoginMessage(vint serverClientId)
{
auto message = CreateJsonObject();
AddJsonObjectField(message, WString::Unmanaged(L"rpcChannelingSystem"), CreateJsonString(WString::Unmanaged(L"Login")));
AddJsonObjectField(message, WString::Unmanaged(L"serverClientId"), CreateJsonNumber(serverClientId));
return message;
}
Ptr<JsonObject> CreateLogoutMessage()
{
auto message = CreateJsonObject();
AddJsonObjectField(message, WString::Unmanaged(L"rpcChannelingSystem"), CreateJsonString(WString::Unmanaged(L"Logout")));
return message;
}
bool TryReadLoginMessage(Ptr<JsonNode> message, vint& serverClientId)
{
if (auto object = message.Cast<JsonObject>())
{
auto systemField = FindJsonObjectField(object, WString::Unmanaged(L"rpcChannelingSystem"));
if (systemField && GetJsonString(systemField) == WString::Unmanaged(L"Login"))
{
serverClientId = GetJsonInt(GetJsonObjectField(object, WString::Unmanaged(L"serverClientId")));
return true;
}
}
return false;
}
}
/***********************************************************************
RpcJsonDispatcherClient
***********************************************************************/
RpcJsonDispatcherClient::RpcJsonDispatcherClient()
{
CHECK_ERROR(semaphoreMessages.Create(0, 65536), L"RpcJsonDispatcherClient failed to create the message semaphore.");
CHECK_ERROR(eventServerLocalClientId.CreateManualUnsignal(false), L"RpcJsonDispatcherClient failed to create the server-client-id event.");
}
void RpcJsonDispatcherClient::PrepareConnection(JsonChannel* channel, const List<WString>& _waitingForServices)
{
CHECK_ERROR(channel, L"RpcJsonDispatcherClient needs an RPC channel.");
CHECK_ERROR(!rpcChannel, L"RpcJsonDispatcherClient connection can only be initialized once.");
rpcChannel = channel;
CopyFrom(waitingForServices, _waitingForServices);
if (waitingForServices.Count() > 0)
{
eventWaitingForServicesCreated = true;
CHECK_ERROR(eventWaitingForServices.CreateManualUnsignal(false), L"RpcJsonDispatcherClient failed to create the service-waiting event.");
}
rpcChannel->Initialize(this);
}
void RpcJsonDispatcherClient::SetRpcObjects(Ptr<RpcJsonDispatcher> _rpcDispatcher, Ptr<RpcJsonLifecycle> _lifecycle)
{
CHECK_ERROR(_rpcDispatcher, L"RpcJsonDispatcherClient needs a dispatcher.");
CHECK_ERROR(_lifecycle, L"RpcJsonDispatcherClient needs a lifecycle.");
CHECK_ERROR(!rpcDispatcher, L"RpcJsonDispatcherClient RPC objects can only be initialized once.");
rpcDispatcher = _rpcDispatcher;
lifecycle = _lifecycle;
}
RpcJsonLifecycle* RpcJsonDispatcherClient::GetRpcJsonLifecycle()
{
CHECK_ERROR(lifecycle, L"RpcJsonDispatcherClient needs a lifecycle.");
return lifecycle.Obj();
}
void RpcJsonDispatcherClient::ProcessCachedIncomingServiceDeclarations()
{
List<JsonPackage> cached;
SPIN_LOCK(lockServiceDeclarations)
{
for (auto request : cachedIncomingServiceDeclarations)
{
cached.Add(request);
}
cachedIncomingServiceDeclarations.Clear();
}
for (auto request : cached)
{
ProcessIncomingServiceDeclaration(request);
}
}
void RpcJsonDispatcherClient::SendCachedOutgoingServiceDeclarations()
{
List<JsonPackage> cached;
SPIN_LOCK(lockServiceDeclarations)
{
for (auto request : cachedOutgoingServiceDeclarations)
{
cached.Add(request);
}
cachedOutgoingServiceDeclarations.Clear();
}
for (auto request : cached)
{
SendJsonRequest(request, RequestType::BroadcastAndDrop);
}
}
void RpcJsonDispatcherClient::ProcessIncomingServiceDeclaration(JsonPackage request)
{
IRpcJsonMessageDispatcher::DefaultTranslate(
request,
RequestType::BroadcastAndDrop,
lifecycle->GetController()->GetObjectOps(),
lifecycle->GetController()->GetObjectEventOps(),
lifecycle->GetDispatcher(),
lifecycle.Obj()
);
UpdateWaitingForServices(request);
}
void RpcJsonDispatcherClient::UpdateWaitingForServices(JsonPackage request)
{
auto typeId = ReadDeclaredServiceTypeId(request);
bool shouldSignal = false;
SPIN_LOCK(lockWaitingForServices)
{
for (vint i = waitingForServices.Count(); i > 0; i--)
{
auto index = i - 1;
if (lifecycle->GetTypeIdFromName(waitingForServices[index]) == typeId)
{
waitingForServices.RemoveAt(index);
}
}
shouldSignal = waitingForServices.Count() == 0;
}
if (shouldSignal && eventWaitingForServicesCreated)
{
eventWaitingForServices.Signal();
}
}
void RpcJsonDispatcherClient::WaitForServerClientId()
{
if (serverLocalClientId.load() == -1)
{
eventServerLocalClientId.Wait();
}
}
void RpcJsonDispatcherClient::WaitForExpectedServices()
{
if (eventWaitingForServicesCreated)
{
eventWaitingForServices.Wait();
}
}
void RpcJsonDispatcherClient::SendJsonRequest(JsonPackage message, RequestType requestType)
{
CHECK_ERROR(rpcChannel, L"RpcJsonDispatcherClient needs an RPC channel.");
switch (requestType)
{
case RequestType::Direct:
rpcChannel->SendToClient(ReadTargetClientId(message), message);
break;
case RequestType::Broadcast:
case RequestType::BroadcastAndDrop:
WaitForServerClientId();
rpcChannel->SendToClient(serverLocalClientId.load(), message);
break;
default:
CHECK_FAIL(L"RpcJsonDispatcherClient received an unknown request type.");
}
FlushChannel();
}
void RpcJsonDispatcherClient::PushReceivedMessage(vint senderClientId, JsonPackage message)
{
SPIN_LOCK(lockMessages)
{
messages.Add({ senderClientId, message });
}
semaphoreMessages.Release();
}
RpcJsonDispatcherClient::ReceivedJsonMessage RpcJsonDispatcherClient::PopReceivedMessage()
{
semaphoreMessages.Wait();
ReceivedJsonMessage result;
SPIN_LOCK(lockMessages)
{
CHECK_ERROR(messages.Count() > 0, L"RpcJsonDispatcherClient message queue is unexpectedly empty.");
result = messages[0];
messages.RemoveAt(0);
}
return result;
}
bool RpcJsonDispatcherClient::TryPopBufferedResponse(vint requestId, ReceivedJsonMessage& message)
{
SPIN_LOCK(lockMessages)
{
for (vint i = 0; i < bufferedResponses.Count(); i++)
{
auto item = bufferedResponses[i];
if (ReadRequestId(item.message) == requestId)
{
message = item;
bufferedResponses.RemoveAt(i);
return true;
}
}
}
return false;
}
void RpcJsonDispatcherClient::PushBufferedResponse(ReceivedJsonMessage message)
{
SPIN_LOCK(lockMessages)
{
bufferedResponses.Add(message);
}
}
void RpcJsonDispatcherClient::SendJsonResponse(vint receiverClientId, JsonPackage response)
{
if (response)
{
CHECK_ERROR(rpcChannel, L"RpcJsonDispatcherClient needs an RPC channel.");
rpcChannel->SendToClient(receiverClientId, response);
FlushChannel();
}
}
void RpcJsonDispatcherClient::FlushChannel()
{
CHECK_ERROR(rpcChannel, L"RpcJsonDispatcherClient needs an RPC channel.");
bool disconnected = false;
rpcChannel->BatchWrite(disconnected);
}
void RpcJsonDispatcherClient::ProcessRequestAndSendResponse(vint senderClientId, JsonPackage request)
{
auto response = TranslateRequest(request);
SendJsonResponse(senderClientId, response);
}
JsonPackage RpcJsonDispatcherClient::TranslateRequest(JsonPackage request)
{
auto rpcMethod = TryReadRpcMethod(request);
CHECK_ERROR(IsRpcRequest(rpcMethod), L"RpcJsonDispatcherClient expects an RPC request.");
return IRpcJsonMessageDispatcher::DefaultTranslate(
request,
GetRequestType(rpcMethod),
lifecycle->GetController()->GetObjectOps(),
lifecycle->GetController()->GetObjectEventOps(),
lifecycle->GetDispatcher(),
lifecycle.Obj()
);
}
void RpcJsonDispatcherClient::WaitForServer(JsonChannelClient* channelClient, JsonChannel* channel, const List<WString>& _waitingForServices)
{
CHECK_ERROR(channelClient, L"RpcJsonDispatcherClient needs a channel client.");
PrepareConnection(channel, _waitingForServices);
channelClient->WaitForServer();
CHECK_ERROR(channelClient->GetStatus() == ClientStatus::Connected, L"RpcJsonDispatcherClient failed to connect to the server.");
}
vint RpcJsonDispatcherClient::ConnectLocalServer(JsonChannelServer* channelServer, Ptr<JsonChannelClient> localClient, JsonChannel* channel, const List<WString>& _waitingForServices)
{
CHECK_ERROR(channelServer, L"RpcJsonDispatcherClient needs a channel server.");
CHECK_ERROR(localClient, L"RpcJsonDispatcherClient needs a local client.");
PrepareConnection(channel, _waitingForServices);
auto clientId = channelServer->ConnectLocalClient(localClient);
CHECK_ERROR(clientId != -1, L"RpcJsonDispatcherClient failed to connect the local client.");
return clientId;
}
void RpcJsonDispatcherClient::Initialize()
{
CHECK_ERROR(lifecycle, L"RpcJsonDispatcherClient needs to connect before Initialize.");
CHECK_ERROR(initialized.load() == 0, L"RpcJsonDispatcherClient can only be initialized once.");
ProcessCachedIncomingServiceDeclarations();
lifecycle->Initialize();
initialized.store(1);
SendCachedOutgoingServiceDeclarations();
WaitForExpectedServices();
}
IRpcLifecycle* RpcJsonDispatcherClient::GetRpcLifecycle()
{
CHECK_ERROR(lifecycle, L"RpcJsonDispatcherClient needs a lifecycle.");
return lifecycle.Obj();
}
IRpcDispatcher* RpcJsonDispatcherClient::GetRpcDispatcher()
{
CHECK_ERROR(rpcDispatcher, L"RpcJsonDispatcherClient needs a dispatcher.");
return rpcDispatcher.Obj();
}
vint RpcJsonDispatcherClient::AllocateRequestId()
{
return ++nextRequestId;
}
JsonPackage RpcJsonDispatcherClient::OnJsonRequest(JsonPackage message, RequestType requestType)
{
auto rpcMethod = TryReadRpcMethod(message);
CHECK_ERROR(rpcMethod != WString::Empty, L"RpcJsonDispatcherClient expects an RPC message.");
if (requestType == RequestType::BroadcastAndDrop)
{
CHECK_ERROR(IsDeclareRemoteServiceRequest(rpcMethod), L"RpcJsonDispatcherClient expects a service declaration.");
if (initialized.load() == 0)
{
SPIN_LOCK(lockServiceDeclarations)
{
cachedOutgoingServiceDeclarations.Add(message);
}
}
else
{
SendJsonRequest(message, requestType);
}
return nullptr;
}
CHECK_ERROR(initialized.load() != 0, L"RpcJsonDispatcherClient only accepts service declarations before Initialize.");
struct ActiveJsonRequest
{
atomic_vint& counter;
ActiveJsonRequest(atomic_vint& _counter)
: counter(_counter)
{
counter++;
}
~ActiveJsonRequest()
{
counter--;
}
};
ActiveJsonRequest active(activeJsonRequests);
auto requestId = ReadRequestId(message);
SendJsonRequest(message, requestType);
while (true)
{
ReceivedJsonMessage item;
if (!TryPopBufferedResponse(requestId, item))
{
item = PopReceivedMessage();
}
rpcMethod = TryReadRpcMethod(item.message);
CHECK_ERROR(rpcMethod != WString::Empty, L"RpcJsonDispatcherClient expects an RPC message.");
if (IsRpcRequest(rpcMethod))
{
ProcessRequestAndSendResponse(item.senderClientId, item.message);
continue;
}
CHECK_ERROR(IsRpcResponse(rpcMethod), L"RpcJsonDispatcherClient expects an RPC request or response.");
if (ReadRequestId(item.message) == requestId)
{
return item.message;
}
PushBufferedResponse(item);
}
}
void RpcJsonDispatcherClient::OnRead(vint senderClientId, const JsonPackage& package)
{
vint newServerLocalClientId = -1;
if (TryReadLoginMessage(package, newServerLocalClientId))
{
serverLocalClientId.store(newServerLocalClientId);
eventServerLocalClientId.Signal();
return;
}
auto rpcMethod = TryReadRpcMethod(package);
CHECK_ERROR(rpcMethod != WString::Empty, L"RpcJsonDispatcherClient expects an RPC message.");
if (IsDeclareRemoteServiceRequest(rpcMethod))
{
if (initialized.load() == 0)
{
SPIN_LOCK(lockServiceDeclarations)
{
cachedIncomingServiceDeclarations.Add(package);
}
}
else
{
ProcessIncomingServiceDeclaration(package);
}
return;
}
CHECK_ERROR(initialized.load() != 0, L"RpcJsonDispatcherClient only accepts service declarations before Initialize.");
if (activeJsonRequests.load() > 0)
{
PushReceivedMessage(senderClientId, package);
return;
}
if (IsRpcRequest(rpcMethod))
{
ScheduleTask(Func<void()>([this, senderClientId, package]()
{
ProcessRequestAndSendResponse(senderClientId, package);
}));
}
else
{
CHECK_ERROR(IsRpcResponse(rpcMethod), L"RpcJsonDispatcherClient expects an RPC request or response.");
CHECK_FAIL(L"RpcJsonDispatcherClient received an RPC response while no request is waiting.");
}
}
void RpcJsonDispatcherClient::FinalizeRpc()
{
if (lifecycle)
{
lifecycle->Finalize();
lifecycle = nullptr;
rpcDispatcher = nullptr;
}
}
void RpcJsonDispatcherClient::SetServerLocalClientId(vint clientId)
{
CHECK_ERROR(clientId != -1, L"RpcJsonDispatcherClient needs a valid server client id.");
serverLocalClientId.store(clientId);
eventServerLocalClientId.Signal();
}
void RpcJsonDispatcherClient::NotifyServerClientDisconnected()
{
CHECK_ERROR(rpcChannel, L"RpcJsonDispatcherClient needs an RPC channel.");
WaitForServerClientId();
rpcChannel->SendToClient(serverLocalClientId.load(), CreateLogoutMessage());
FlushChannel();
}
/***********************************************************************
RpcJsonDispatcherClientForTaskQueue
***********************************************************************/
void RpcJsonDispatcherClientForTaskQueue::ScheduleTask(Func<void()> task)
{
taskQueue->QueueTask(task);
}
RpcJsonDispatcherClientForTaskQueue::RpcJsonDispatcherClientForTaskQueue(Ptr<TaskQueue> _taskQueue)
: taskQueue(_taskQueue)
{
CHECK_ERROR(taskQueue, L"RpcJsonDispatcherClientForTaskQueue needs a task queue.");
}
}
/***********************************************************************
.\RPCJSON\WFLIBRARYRPCJSONDISPATCHERSERVER.CPP
***********************************************************************/
namespace vl::rpc_controller::channeling
{
using namespace vl;
using namespace vl::collections;
using namespace vl::glr::json;
namespace
{
Ptr<JsonLiteral> ServerCreateJsonLiteral(JsonLiteralValue value)
{
auto node = Ptr(new JsonLiteral);
node->value = value;
return node;
}
Ptr<JsonString> ServerCreateJsonString(const WString& value)
{
auto node = Ptr(new JsonString);
node->content.value = value;
return node;
}
Ptr<JsonNumber> ServerCreateJsonNumber(vint value)
{
auto node = Ptr(new JsonNumber);
node->content.value = itow(value);
return node;
}
Ptr<JsonArray> ServerCreateJsonArray()
{
return Ptr(new JsonArray);
}
Ptr<JsonObject> ServerCreateJsonObject()
{
return Ptr(new JsonObject);
}
Ptr<JsonObject> ServerGetJsonObject(Ptr<JsonNode> node)
{
auto object = node.Cast<JsonObject>();
CHECK_ERROR(object, L"RpcJsonDispatcherServer expects a JSON object.");
return object;
}
Ptr<JsonArray> ServerGetJsonArray(Ptr<JsonNode> node)
{
auto array = node.Cast<JsonArray>();
CHECK_ERROR(array, L"RpcJsonDispatcherServer expects a JSON array.");
return array;
}
void ServerAddJsonObjectField(Ptr<JsonObject> object, const WString& name, Ptr<JsonNode> value)
{
auto field = Ptr(new JsonObjectField);
field->name.value = name;
field->value = value;
object->fields.Add(field);
}
void ServerSetJsonObjectField(Ptr<JsonObject> object, const WString& name, Ptr<JsonNode> value)
{
for (auto field : object->fields)
{
if (field->name.value == name)
{
field->value = value;
return;
}
}
ServerAddJsonObjectField(object, name, value);
}
Ptr<JsonNode> ServerFindJsonObjectField(Ptr<JsonObject> object, const WString& name)
{
for (auto field : object->fields)
{
if (field->name.value == name)
{
return field->value;
}
}
return nullptr;
}
Ptr<JsonNode> ServerGetJsonObjectField(Ptr<JsonObject> object, const WString& name)
{
auto field = ServerFindJsonObjectField(object, name);
CHECK_ERROR(field, L"RpcJsonDispatcherServer expects a JSON object field.");
return field;
}
WString ServerGetJsonString(Ptr<JsonNode> node)
{
auto stringNode = node.Cast<JsonString>();
CHECK_ERROR(stringNode, L"RpcJsonDispatcherServer expects a JSON string.");
return stringNode->content.value;
}
vint ServerGetJsonInt(Ptr<JsonNode> node)
{
auto numberNode = node.Cast<JsonNumber>();
CHECK_ERROR(numberNode, L"RpcJsonDispatcherServer expects a JSON number.");
return wtoi(numberNode->content.value);
}
bool ServerIsJsonNull(Ptr<JsonNode> node)
{
auto literal = node.Cast<JsonLiteral>();
return literal && literal->value == JsonLiteralValue::Null;
}
bool ServerStartsWith(const WString& value, const wchar_t* prefix)
{
auto prefixLength = (vint)wcslen(prefix);
return value.Length() >= prefixLength && wcsncmp(value.Buffer(), prefix, prefixLength) == 0;
}
WString ServerTryReadRpcMethod(Ptr<JsonNode> message)
{
if (auto object = message.Cast<JsonObject>())
{
if (auto field = ServerFindJsonObjectField(object, WString::Unmanaged(L"rpcMethod")))
{
if (auto stringNode = field.Cast<JsonString>())
{
return stringNode->content.value;
}
}
}
return WString::Empty;
}
bool ServerIsRpcRequest(const WString& rpcMethod)
{
return ServerStartsWith(rpcMethod, L"Request:");
}
bool ServerIsRpcResponse(const WString& rpcMethod)
{
return ServerStartsWith(rpcMethod, L"Response:");
}
bool ServerIsBroadcastRequest(const WString& rpcMethod)
{
return rpcMethod == WString::Unmanaged(L"Request:IObjectEventOps_InvokeEvent");
}
bool ServerIsBroadcastAndDropRequest(const WString& rpcMethod)
{
return rpcMethod == WString::Unmanaged(L"Request:IRpcDispatcher_DeclareRemoteService");
}
vint ServerReadRequestId(Ptr<JsonNode> message)
{
return ServerGetJsonInt(ServerGetJsonObjectField(ServerGetJsonObject(message), WString::Unmanaged(L"rpcRequestId")));
}
void ServerWriteRequestId(Ptr<JsonNode> message, vint requestId)
{
ServerSetJsonObjectField(ServerGetJsonObject(message), WString::Unmanaged(L"rpcRequestId"), ServerCreateJsonNumber(requestId));
}
vint ServerReadSourceClientId(Ptr<JsonNode> message)
{
return ServerGetJsonInt(ServerGetJsonObjectField(ServerGetJsonObject(message), WString::Unmanaged(L"sourceClientId")));
}
void ServerWriteSourceClientId(Ptr<JsonNode> message, vint clientId)
{
ServerSetJsonObjectField(ServerGetJsonObject(message), WString::Unmanaged(L"sourceClientId"), ServerCreateJsonNumber(clientId));
}
Ptr<JsonObject> ServerCreateRpcMessage(const WString& rpcMethod, vint requestId, vint sourceClientId)
{
auto message = ServerCreateJsonObject();
ServerAddJsonObjectField(message, WString::Unmanaged(L"rpcMethod"), ServerCreateJsonString(rpcMethod));
ServerAddJsonObjectField(message, WString::Unmanaged(L"rpcRequestId"), ServerCreateJsonNumber(requestId));
ServerAddJsonObjectField(message, WString::Unmanaged(L"sourceClientId"), ServerCreateJsonNumber(sourceClientId));
return message;
}
Ptr<JsonObject> ServerCreateLoginMessage(vint serverClientId)
{
auto message = ServerCreateJsonObject();
ServerAddJsonObjectField(message, WString::Unmanaged(L"rpcChannelingSystem"), ServerCreateJsonString(WString::Unmanaged(L"Login")));
ServerAddJsonObjectField(message, WString::Unmanaged(L"serverClientId"), ServerCreateJsonNumber(serverClientId));
return message;
}
bool ServerTryReadLogoutMessage(Ptr<JsonNode> message)
{
if (auto object = message.Cast<JsonObject>())
{
auto systemField = ServerFindJsonObjectField(object, WString::Unmanaged(L"rpcChannelingSystem"));
return systemField && ServerGetJsonString(systemField) == WString::Unmanaged(L"Logout");
}
return false;
}
bool ServerIsBroadcastReady(Ptr<RpcJsonDispatcherServer::PendingBroadcast> pending)
{
for (auto clientId : pending->expectedClientIds)
{
if (!pending->responses.Keys().Contains(clientId))
{
return false;
}
}
return true;
}
}
/***********************************************************************
RpcJsonDispatcherServer
***********************************************************************/
RpcJsonDispatcherServer::RpcJsonDispatcherServer(JsonChannelClient* _serverClient, JsonChannel* channel)
{
CHECK_ERROR(_serverClient, L"RpcJsonDispatcherServer needs a server channel client.");
CHECK_ERROR(channel, L"RpcJsonDispatcherServer needs an RPC channel.");
serverClient = _serverClient;
rpcChannel = channel;
rpcChannel->Initialize(this);
}
vint RpcJsonDispatcherServer::AllocateRequestId()
{
return ++nextRequestId;
}
WString RpcJsonDispatcherServer::MakeBroadcastKey(vint clientId, vint requestId)
{
return itow(clientId) + WString::Unmanaged(L":") + itow(requestId);
}
JsonPackage RpcJsonDispatcherServer::CreateBroadcastResponse(vint sourceClientId, vint targetClientId, vint requestId, Ptr<PendingBroadcast> pending)
{
auto response = ServerCreateRpcMessage(WString::Unmanaged(L"Response:Broadcast_Response"), requestId, sourceClientId);
ServerAddJsonObjectField(response, WString::Unmanaged(L"targetClientId"), ServerCreateJsonNumber(targetClientId));
if (pending && pending->hasNonNullResponse)
{
auto consolidated = ServerCreateJsonArray();
for (auto clientId : pending->expectedClientIds)
{
auto index = pending->responses.Keys().IndexOf(clientId);
if (index != -1)
{
auto responseObject = ServerGetJsonObject(pending->responses.Values()[index]);
auto responseField = ServerFindJsonObjectField(responseObject, WString::Unmanaged(L"response"));
if (responseField && !ServerIsJsonNull(responseField))
{
auto array = ServerGetJsonArray(responseField);
for (auto item : array->items)
{
consolidated->items.Add(item);
}
}
}
}
ServerAddJsonObjectField(response, WString::Unmanaged(L"response"), consolidated);
}
else
{
ServerAddJsonObjectField(response, WString::Unmanaged(L"response"), ServerCreateJsonLiteral(JsonLiteralValue::Null));
}
return response;
}
RpcJsonDispatcherServer::CompletedBroadcast RpcJsonDispatcherServer::CompleteBroadcastLocked(const WString& key)
{
auto pending = pendingBroadcasts[key];
auto serverClientId = GetServerClientId();
CompletedBroadcast completed;
completed.originalClientId = pending->originalClientId;
completed.response = CreateBroadcastResponse(serverClientId, pending->originalClientId, pending->originalRequestId, pending);
redirectedBroadcasts.Remove(pending->redirectedRequestId);
pendingBroadcasts.Remove(key);
return completed;
}
void RpcJsonDispatcherServer::DeliverCompletedBroadcast(const CompletedBroadcast& completed)
{
if (completed.response)
{
SendJsonResponse(completed.originalClientId, completed.response);
}
}
JsonPackage RpcJsonDispatcherServer::StartBroadcast(vint originalClientId, vint originalRequestId, JsonPackage message)
{
auto serverClientId = GetServerClientId();
auto redirectedRequestId = AllocateRequestId();
copy_visitor::AstVisitor copier;
auto redirectedMessage = copier.CopyNode(message.Obj());
ServerWriteRequestId(redirectedMessage, redirectedRequestId);
ServerWriteSourceClientId(redirectedMessage, serverClientId);
JsonPackage immediateResponse;
bool shouldFlush = false;
List<vint> blockedReceivers;
auto pending = Ptr(new PendingBroadcast);
pending->originalClientId = originalClientId;
pending->originalRequestId = originalRequestId;
pending->redirectedRequestId = redirectedRequestId;
SPIN_LOCK(lockBroadcasts)
{
for (auto clientId : connectedClientIds)
{
if (clientId != originalClientId)
{
pending->expectedClientIds.Add(clientId);
}
}
if (pending->expectedClientIds.Count() == 0)
{
immediateResponse = CreateBroadcastResponse(serverClientId, originalClientId, originalRequestId, nullptr);
}
else
{
auto key = MakeBroadcastKey(originalClientId, originalRequestId);
pendingBroadcasts.Add(key, pending);
redirectedBroadcasts.Add(redirectedRequestId, key);
if (connectedClientIds.Contains(originalClientId))
{
blockedReceivers.Add(originalClientId);
}
CHECK_ERROR(rpcChannel, L"RpcJsonDispatcherServer needs an RPC channel.");
rpcChannel->BroadcastFromClient(redirectedMessage, blockedReceivers);
shouldFlush = true;
}
}
if (shouldFlush)
{
FlushChannel();
}
return immediateResponse;
}
void RpcJsonDispatcherServer::StartBroadcastAndDrop(vint originalClientId, JsonPackage message)
{
List<vint> blockedReceivers;
SPIN_LOCK(lockBroadcasts)
{
if (connectedClientIds.Contains(originalClientId))
{
blockedReceivers.Add(originalClientId);
}
CHECK_ERROR(rpcChannel, L"RpcJsonDispatcherServer needs an RPC channel.");
rpcChannel->BroadcastFromClient(message, blockedReceivers);
}
FlushChannel();
}
bool RpcJsonDispatcherServer::TryHandleBroadcastResponse(vint senderClientId, JsonPackage response)
{
if (ServerTryReadRpcMethod(response) != WString::Unmanaged(L"Response:Broadcast_Response"))
{
return false;
}
CompletedBroadcast completed;
auto redirectedRequestId = ServerReadRequestId(response);
bool handled = false;
SPIN_LOCK(lockBroadcasts)
{
auto index = redirectedBroadcasts.Keys().IndexOf(redirectedRequestId);
if (index != -1)
{
handled = true;
auto key = redirectedBroadcasts.Values()[index];
auto pending = pendingBroadcasts[key];
if (pending->expectedClientIds.Contains(senderClientId))
{
auto responseObject = ServerGetJsonObject(response);
auto responseField = ServerFindJsonObjectField(responseObject, WString::Unmanaged(L"response"));
if (responseField && !ServerIsJsonNull(responseField))
{
pending->hasNonNullResponse = true;
}
pending->responses.Set(senderClientId, response);
if (ServerIsBroadcastReady(pending))
{
completed = CompleteBroadcastLocked(key);
}
}
}
}
DeliverCompletedBroadcast(completed);
return handled;
}
void RpcJsonDispatcherServer::HandleServiceDeclaration(vint senderClientId, JsonPackage request)
{
SPIN_LOCK(lockBroadcasts)
{
cachedServiceDeclarations.Add(request);
}
StartBroadcastAndDrop(senderClientId, request);
}
void RpcJsonDispatcherServer::SendLoginMessages(vint clientId)
{
List<JsonPackage> declarations;
SPIN_LOCK(lockBroadcasts)
{
for (auto request : cachedServiceDeclarations)
{
declarations.Add(request);
}
}
CHECK_ERROR(rpcChannel, L"RpcJsonDispatcherServer needs an RPC channel.");
rpcChannel->SendToClient(clientId, ServerCreateLoginMessage(GetServerClientId()));
for (auto request : declarations)
{
rpcChannel->SendToClient(clientId, request);
}
FlushChannel();
}
void RpcJsonDispatcherServer::SendJsonResponse(vint receiverClientId, JsonPackage response)
{
CHECK_ERROR(rpcChannel, L"RpcJsonDispatcherServer needs an RPC channel.");
rpcChannel->SendToClient(receiverClientId, response);
FlushChannel();
}
void RpcJsonDispatcherServer::FlushChannel()
{
CHECK_ERROR(rpcChannel, L"RpcJsonDispatcherServer needs an RPC channel.");
bool disconnected = false;
rpcChannel->BatchWrite(disconnected);
}
bool RpcJsonDispatcherServer::HasServerClientId()
{
return serverClient->GetClientId() != -1;
}
void RpcJsonDispatcherServer::RegisterClient(vint clientId)
{
CHECK_ERROR(clientId != -1, L"RpcJsonDispatcherServer needs a valid client id.");
CHECK_ERROR(HasServerClientId(), L"RpcJsonDispatcherServer needs its server local client to connect first.");
SPIN_LOCK(lockBroadcasts)
{
if (!connectedClientIds.Contains(clientId))
{
connectedClientIds.Add(clientId);
}
}
ScheduleTask(Func<void()>([this, clientId]()
{
SendLoginMessages(clientId);
}));
}
void RpcJsonDispatcherServer::DisconnectClient(vint clientId)
{
if (clientId == GetServerClientId())
{
return;
}
List<CompletedBroadcast> completedBroadcasts;
SPIN_LOCK(lockBroadcasts)
{
if (connectedClientIds.Contains(clientId))
{
connectedClientIds.Remove(clientId);
}
for (vint i = pendingBroadcasts.Count(); i > 0; i--)
{
auto index = i - 1;
auto key = pendingBroadcasts.Keys().Get(index);
auto pending = pendingBroadcasts.Values().Get(index);
auto expectedIndex = pending->expectedClientIds.IndexOf(clientId);
if (expectedIndex != -1)
{
pending->expectedClientIds.RemoveAt(expectedIndex);
if (ServerIsBroadcastReady(pending))
{
completedBroadcasts.Add(CompleteBroadcastLocked(key));
}
}
}
}
for (auto&& completed : completedBroadcasts)
{
DeliverCompletedBroadcast(completed);
}
}
vint RpcJsonDispatcherServer::GetServerClientId()
{
auto result = serverClient->GetClientId();
CHECK_ERROR(result != -1, L"RpcJsonDispatcherServer server client has not been connected.");
return result;
}
void RpcJsonDispatcherServer::OnRead(vint senderClientId, const JsonPackage& package)
{
if (ServerTryReadLogoutMessage(package))
{
DisconnectClient(senderClientId);
return;
}
auto rpcMethod = ServerTryReadRpcMethod(package);
CHECK_ERROR(rpcMethod != WString::Empty, L"RpcJsonDispatcherServer expects an RPC message.");
if (ServerIsRpcRequest(rpcMethod))
{
auto originalClientId = ServerReadSourceClientId(package);
CHECK_ERROR(originalClientId == senderClientId, L"RpcJsonDispatcherServer received a request with a mismatched source client id.");
if (ServerIsBroadcastAndDropRequest(rpcMethod))
{
HandleServiceDeclaration(originalClientId, package);
}
else if (ServerIsBroadcastRequest(rpcMethod))
{
auto immediateResponse = StartBroadcast(originalClientId, ServerReadRequestId(package), package);
if (immediateResponse)
{
SendJsonResponse(originalClientId, immediateResponse);
}
}
else
{
CHECK_FAIL(L"RpcJsonDispatcherServer only accepts broadcast requests.");
}
return;
}
CHECK_ERROR(ServerIsRpcResponse(rpcMethod), L"RpcJsonDispatcherServer expects an RPC request or response.");
if (!TryHandleBroadcastResponse(senderClientId, package))
{
CHECK_FAIL(L"RpcJsonDispatcherServer received an unmatched RPC response.");
}
}
/***********************************************************************
RpcJsonDispatcherServerForTaskQueue
***********************************************************************/
void RpcJsonDispatcherServerForTaskQueue::ScheduleTask(Func<void()> task)
{
taskQueue->QueueTask(task);
}
RpcJsonDispatcherServerForTaskQueue::RpcJsonDispatcherServerForTaskQueue(JsonChannelClient* _serverClient, JsonChannel* channel, Ptr<TaskQueue> _taskQueue)
: RpcJsonDispatcherServer(_serverClient, channel)
, taskQueue(_taskQueue)
{
CHECK_ERROR(taskQueue, L"RpcJsonDispatcherServerForTaskQueue needs a task queue.");
}
}