/*********************************************************************** 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 _list) :list(_list) { } /*********************************************************************** CreateList ***********************************************************************/ CreateList::CreateList() :list(IValueList::Create()) { } CreateList::CreateList(Ptr _list) :list(_list) { } /*********************************************************************** CreateObservableList ***********************************************************************/ CreateObservableList::CreateObservableList() :list(IValueObservableList::Create()) { } CreateObservableList::CreateObservableList(Ptr _list) :list(_list) { } /*********************************************************************** CreateDictionary ***********************************************************************/ CreateDictionary::CreateDictionary() :dictionary(IValueDictionary::Create()) { } CreateDictionary::CreateDictionary(Ptr _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 CoroutineResult::GetFailure() { return failure; } void CoroutineResult::SetFailure(Ptr value) { failure = value; } /*********************************************************************** EnumerableCoroutine ***********************************************************************/ class CoroutineEnumerator : public Object, public virtual EnumerableCoroutine::IImpl, public Description { protected: EnumerableCoroutine::Creator creator; Ptr coroutine; Value current; vint index = -1; Ptr 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 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 { protected: EnumerableCoroutine::Creator creator; public: CoroutineEnumerable(const EnumerableCoroutine::Creator& _creator) :creator(_creator) { } Ptr CreateEnumerator()override { return Ptr(new CoroutineEnumerator(creator)); } }; void EnumerableCoroutine::YieldAndPause(IImpl* impl, const Value& value) { impl->OnYield(value); } void EnumerableCoroutine::JoinAndPause(IImpl* impl, Ptr value) { impl->OnJoin(value); } void EnumerableCoroutine::ReturnAndExit(IImpl* impl) { } Ptr 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 { protected: SpinLock lock; vint milliseconds; AsyncStatus status = AsyncStatus::Ready; public: DelayAsync(vint _milliseconds) :milliseconds(_milliseconds) { } AsyncStatus GetStatus()override { return status; } bool Execute(const Func)>& _callback, Ptr context)override { SPIN_LOCK(lock) { if (status != AsyncStatus::Ready) return false; status = AsyncStatus::Executing; IAsyncScheduler::GetSchedulerForCurrentThread()->DelayExecute([async = Ptr(this), callback = _callback]() { if (callback) { callback(nullptr); } }, milliseconds); } return true; } }; Ptr IAsync::Delay(vint milliseconds) { return Ptr(new DelayAsync(milliseconds)); } /*********************************************************************** FutureAndPromiseAsync ***********************************************************************/ class FutureAndPromiseAsync : public virtual IFuture, public virtual IPromise, public Description { public: SpinLock lock; AsyncStatus status = AsyncStatus::Ready; Ptr cr; Func)> callback; void ExecuteCallbackAndClear() { status = AsyncStatus::Stopped; if (callback) { callback(cr); } cr = nullptr; callback = {}; } template 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)>& _callback, Ptr context)override { SPIN_LOCK(lock) { if (status != AsyncStatus::Ready) return false; callback = _callback; if (cr) { ExecuteCallbackAndClear(); } else { status = AsyncStatus::Executing; } } return true; } Ptr GetPromise()override { return Ptr(this); } bool SendResult(const Value& result)override { return Send([=, this]() { cr->SetResult(result); }); } bool SendFailure(Ptr failure)override { return Send([=, this]() { cr->SetFailure(failure); }); } }; Ptr IFuture::Create() { return Ptr(new FutureAndPromiseAsync); } /*********************************************************************** IAsyncScheduler ***********************************************************************/ class AsyncSchedulerMap { public: Dictionary> schedulers; Ptr 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 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 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::UnregisterDefaultScheduler() { Ptr scheduler; SPIN_LOCK(asyncSchedulerLock) { if (asyncSchedulerMap) { scheduler = asyncSchedulerMap->defaultScheduler; asyncSchedulerMap->defaultScheduler = nullptr; DISPOSE_ASYNC_SCHEDULER_MAP_IF_NECESSARY } } return scheduler; } Ptr IAsyncScheduler::UnregisterSchedulerForCurrentThread() { Ptr 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::GetSchedulerForCurrentThread() { Ptr 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 { protected: Ptr coroutine; AsyncCoroutine::Creator creator; Ptr scheduler; Func)> callback; Ptr 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)>& _callback, Ptr _context)override { if (coroutine) return false; scheduler = IAsyncScheduler::GetSchedulerForCurrentThread(); callback = _callback; context = _context; coroutine = creator(this); OnContinue(nullptr); return true; } Ptr GetScheduler()override { return scheduler; } Ptr GetContext()override { if (!context) { context = Ptr(new AsyncContext); } return context; } void OnContinue(Ptr output)override { scheduler->Execute([async = Ptr(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 value) { value->Execute([async = Ptr(impl)](auto output) { async->OnContinue(output); }, impl->GetContext()); } void AsyncCoroutine::ReturnAndExit(IImpl* impl, const Value& value) { impl->OnReturn(value); } Ptr AsyncCoroutine::QueryContext(IImpl* impl) { return impl->GetContext(); } Ptr AsyncCoroutine::Create(const Creator& creator) { return Ptr(new CoroutineAsync(creator)); } void AsyncCoroutine::CreateAndRun(const Creator& creator) { Ptr(new CoroutineAsync(creator))->Execute( [](Ptr 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 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 list; class Enumerator : public Object, public IValueEnumerator { protected: Ptr list; vint index; public: Enumerator(Ptr _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 _list) :list(_list) { } Ptr 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 Sys::ReverseEnumerable(Ptr value) { auto list = value.Cast(); if (!list) { list = IValueList::Create(GetLazyList(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 Localization::Locales() { auto result = Ptr(new List); Locale::Enumerate(*result.Obj()); return result; } collections::LazyList Localization::GetShortDateFormats(Locale locale) { auto result = Ptr(new List); locale.GetShortDateFormats(*result.Obj()); return result; } collections::LazyList Localization::GetLongDateFormats(Locale locale) { auto result = Ptr(new List); locale.GetLongDateFormats(*result.Obj()); return result; } collections::LazyList Localization::GetYearMonthDateFormats(Locale locale) { auto result = Ptr(new List); locale.GetYearMonthDateFormats(*result.Obj()); return result; } collections::LazyList Localization::GetLongTimeFormats(Locale locale) { auto result = Ptr(new List); locale.GetLongTimeFormats(*result.Obj()); return result; } collections::LazyList Localization::GetShortTimeFormats(Locale locale) { auto result = Ptr(new List); 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 #include 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(), 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::rpc_controller::IRpcLifecycle*), vl::rpc_controller::RpcBoxByref) CLASS_MEMBER_STATIC_EXTERNALMETHOD(RpcUnboxByref, { L"serializable" _ L"lc" }, vl::Ptr(*)(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(*)(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(*)(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(), 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(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(), 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(), 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>(); } RpcObjectReference GetRpcObjectReference(const Value& value) { auto boxed = value.GetBoxedValue().Cast>(); 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 bool ContainsKey(const Dictionary& xs, const K& key) { return xs.Keys().Contains(key); } template Ptr TryGetValueInterface(const Value& value) { if (auto raw = value.GetRawPtr()) { return Ptr(dynamic_cast(raw)); } return nullptr; } Value RpcCopyValueByvalInternal(const Value& trivial, Dictionary& visited) { if (trivial.IsNull()) return trivial; if (trivial.GetValueType() == Value::SharedPtr) { if (auto roDict = TryGetValueInterface(trivial)) { auto key = static_cast(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(trivial)) { auto key = static_cast(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(trivial)) { auto key = static_cast(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(trivial)) { auto key = static_cast(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& visited) { if (trivial.IsNull()) return trivial; if (trivial.GetValueType() == Value::SharedPtr) { if (auto roDict = TryGetValueInterface(trivial)) { auto key = static_cast(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(trivial)) { auto key = static_cast(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(trivial)) { auto key = static_cast(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(trivial)) { auto key = static_cast(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(raw)) { auto ref = lc->PtrToRef(Ptr(obj)); return BoxValue(ref); } } } return trivial; } Value RpcUnboxValueByvalInternal(const Value& serializable, IRpcLifecycle* lc, Dictionary& 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(serializable)) { auto key = static_cast(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(serializable)) { auto key = static_cast(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(serializable)) { auto key = static_cast(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(serializable)) { auto key = static_cast(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 trivial, IRpcLifecycle* lc) { if (!lc) CHECK_FAIL(L"IRpcLifecycle cannot be null."); if (!trivial) return {}; return lc->PtrToRef(trivial); } Ptr 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 visited; return RpcCopyValueByvalInternal(trivial, visited); } Value RpcBoxByval(Ptr 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 visited; return RpcBoxValueByvalInternal(trivial, lc, visited); } Ptr RpcUnboxByval(const Value& serializable, IRpcLifecycle* lc) { if (!lc) CHECK_FAIL(L"IRpcLifecycle cannot be null."); if (serializable.IsNull()) return nullptr; Dictionary visited; auto trivial = RpcUnboxValueByvalInternal(serializable, lc, visited); if (auto raw = trivial.GetRawPtr()) { if (auto obj = dynamic_cast(raw)) { return Ptr(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>()) { 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(exceptions->Get(key)); message += itow(UnboxValue(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 _objectCallback, Ptr _eventCallback) { objectCallback = _objectCallback; eventCallback = _eventCallback; } IRpcObjectOps* RpcControllerDefault::GetObjectOps() { return objectCallback.Obj(); } IRpcObjectEventOps* RpcControllerDefault::GetObjectEventOps() { return eventCallback.Obj(); } void RpcControllerDefault::Finalize() { } template void RpcControllerDefault::SetSuppressedFlag(Dictionary& flags, const TKey& key, bool suppressed) { #define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcControllerDefault::SetSuppressedFlag(collections::Dictionary&, 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 bool RpcControllerDefault::GetSuppressedFlag(const Dictionary& 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(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& _idMap) { CopyFrom(idMap, _idMap); } void RpcLifecycleBase::SetSerializer(Ptr _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(); 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(obj)) return RpcTypeId_IValueObservableList; if (dynamic_cast(obj)) return RpcTypeId_IValueDictionary; if (dynamic_cast(obj)) return RpcTypeId_IValueArray; if (dynamic_cast(obj)) return RpcTypeId_IValueList; if (dynamic_cast(obj)) return RpcTypeId_IValueReadonlyList; if (dynamic_cast(obj)) return RpcTypeId_IValueEnumerator; if (dynamic_cast(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(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(obj)) { Ptr tracker; if (auto trackerObj = descriptable->GetInternalProperty(InternalProperty_LocalObjectTracker)) { tracker = trackerObj.Cast(); 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 obj, RpcObjectReference ref) { #define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcLifecycleBase::CreateLocalObject(Ptr, 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(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(rawPtr)) { if (auto trackerObj = descriptable->GetInternalProperty(InternalProperty_LocalObjectTracker)) { auto tracker = trackerObj.Cast(); 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(); 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 RpcLifecycleBase::CreateCallerProxy(RpcObjectReference ref, IRpcSerializer* serializer) { #define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcLifecycleBase::CreateCallerProxy(RpcObjectReference)#" IRpcLifecycle* lc = this; Ptr 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(wrapper.Obj()); CHECK_ERROR(descriptable, ERROR_MESSAGE_PREFIX L"Wrapper does not implement IDescriptable."); auto root = dynamic_cast(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 service) { #define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcLifecycleBase::RegisterLocalService(vint, Ptr)#" 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 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 RpcLifecycleBase::RefToPtr(RpcObjectReference ref) { return RefToPtr(ref, serializer.Obj()); } Ptr 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(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 obj) { #define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcLifecycleBase::PtrToRef(Ptr)#" CHECK_ERROR(obj, ERROR_MESSAGE_PREFIX L"A value is required."); if (auto descObj = dynamic_cast(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(obj.Obj())) { if (auto trackerObj = descObj->GetInternalProperty(InternalProperty_LocalObjectTracker)) { auto tracker = trackerObj.Cast(); 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>(); } RpcObjectReference GetRpcObjectReference(const Value& value) { auto boxed = value.GetBoxedValue().Cast>(); CHECK_ERROR(boxed, L"RpcObjectReference is expected."); return boxed->value; } #endif IRpcWrapperBase* CastRpcWrapperBase(IDescriptable* obj) { if (!obj) return nullptr; if (auto wrapper = dynamic_cast(obj)) return wrapper; return obj->SafeAggregationCast(); } template TInterface* CastRpcInterface(IDescriptable* obj) { if (!obj) return nullptr; if (auto proxy = dynamic_cast(obj)) return proxy; return obj->SafeAggregationCast(); } template Ptr CreateTrackedProxy(IRpcLifecycle* lc, RpcObjectReference ref, IRpcSerializer* serializer) { auto obj = [&]() { if (auto lifecycle = dynamic_cast(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(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 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 Ptr CreateRpcArguments(TArgs&& ...args) { auto arguments = IValueArray::Create(); arguments->Resize(sizeof...(TArgs)); vint index = 0; ((arguments->Set(index++, std::forward(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 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(raw)) { return BoxValue(RpcBoxByref(Ptr(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 RpcByrefEnumerable::CreateEnumerator() { return CreateTrackedProxy(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 RpcByrefReadonlyList::CreateEnumerator() { return CreateTrackedProxy(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 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 RpcByrefArray::CreateEnumerator() { return CreateTrackedProxy(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 RpcByrefObservableList::CreateEnumerator() { return CreateTrackedProxy(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 RpcByrefDictionary::GetKeys() { return CreateTrackedProxy(lifecycle, GetRemoteListOps(lifecycle, ref, serializer)->DictGetKeys(ref), serializer); } Ptr RpcByrefDictionary::GetValues() { return CreateTrackedProxy(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 enumerator; if (auto xs = Ptr(obj.Obj()->SafeAggregationCast())) { 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()); 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()); 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())) 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())) 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())) { array->Set(index, trivial); return; } if (auto list = Ptr(obj.Obj()->SafeAggregationCast())) { 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())) 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())) 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())) 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())) { 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())) 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())) 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()); 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()); 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()); 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()); 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()); 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()); 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()); 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()); 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()); 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()); 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 _listOps, Ptr _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 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(DeserializeValue(serializer, arguments->Get(0)))); case RpcMethodId_IValueList_Set: listOps->ListSet(ref, UnboxValue(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(DeserializeValue(serializer, arguments->Get(0))), arguments->Get(1)))); case RpcMethodId_IValueList_RemoveAt: return SerializeValue(serializer, BoxValue(listOps->ListRemoveAt(ref, UnboxValue(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(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 _listEventOps, Ptr _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 arguments) { if (eventId == RpcEventId_IValueObservableList_ItemChanged) { return listEventOps->OnItemChanged( ref, UnboxValue(DeserializeValue(serializer, arguments->Get(0))), UnboxValue(DeserializeValue(serializer, arguments->Get(1))), UnboxValue(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(result); } bool RpcCallerListOps::EnumNext(RpcObjectReference enumerator) { auto result = InvokeListMethod(objectOps, serializer, enumerator, RpcMethodId_IValueEnumerator_Next, CreateRpcArguments()); return UnboxValue(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(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(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(result); } bool RpcCallerListOps::ListRemoveAt(RpcObjectReference ref, vint index) { auto result = InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueList_RemoveAt, CreateRpcArguments(SerializeValue(serializer, BoxValue(index)))); return UnboxValue(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(result); } vint RpcCallerListOps::ListIndexOf(RpcObjectReference ref, const Value& value) { auto result = InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueReadonlyList_IndexOf, CreateRpcArguments(value)); return UnboxValue(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(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(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(result); } RpcObjectReference RpcCallerListOps::DictGetKeys(RpcObjectReference ref) { auto result = InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueReadonlyDictionary_GetKeys, CreateRpcArguments()); return UnboxValue(result); } RpcObjectReference RpcCallerListOps::DictGetValues(RpcObjectReference ref) { auto result = InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueReadonlyDictionary_GetValues, CreateRpcArguments()); return UnboxValue(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(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 CreateJsonLiteral(JsonLiteralValue value) { auto node = Ptr(new JsonLiteral); node->value = value; return node; } Ptr CreateJsonString(const WString& value) { auto node = Ptr(new JsonString); node->content.value = value; return node; } Ptr CreateJsonNumber(const WString& value) { auto node = Ptr(new JsonNumber); node->content.value = value; return node; } Ptr CreateJsonArray() { return Ptr(new JsonArray); } Ptr CreateJsonObject() { return Ptr(new JsonObject); } Ptr GetJsonObject(Ptr node) { auto object = node.Cast(); CHECK_ERROR(object, L"JSON object is expected."); return object; } Ptr GetJsonArray(Ptr node) { auto array = node.Cast(); CHECK_ERROR(array, L"JSON array is expected."); return array; } void AddJsonObjectField(Ptr object, const WString& name, Ptr value) { auto field = Ptr(new JsonObjectField); field->name.value = name; field->value = value; object->fields.Add(field); } void SetJsonObjectField(Ptr object, const WString& name, Ptr value) { for (auto field : object->fields) { if (field->name.value == name) { field->value = value; return; } } AddJsonObjectField(object, name, value); } Ptr GetJsonObjectField(Ptr 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 FindJsonObjectField(Ptr object, const WString& name) { for (auto field : object->fields) { if (field->name.value == name) { return field->value; } } return nullptr; } WString GetJsonString(Ptr node) { auto stringNode = node.Cast(); CHECK_ERROR(stringNode, L"JSON string is expected."); return stringNode->content.value; } WString GetJsonNumber(Ptr node) { auto numberNode = node.Cast(); CHECK_ERROR(numberNode, L"JSON number is expected."); return numberNode->content.value; } vint GetJsonInt(Ptr node) { return __vwsn::Parse(GetJsonNumber(node)); } bool GetJsonBool(Ptr node) { auto literal = node.Cast(); 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 CreateJsonNumber(vint value) { return CreateJsonNumber(__vwsn::ToString(value)); } Ptr CreateJsonBool(bool value) { return CreateJsonLiteral(value ? JsonLiteralValue::True : JsonLiteralValue::False); } Ptr CreateUnknownTuple(const WString& keyword, Ptr value) { auto array = CreateJsonArray(); array->items.Add(CreateJsonString(keyword)); array->items.Add(value); return Ptr(array); } template bool TrySerializeNumberPrimitive(const Value& value, const WString& keyword, Ptr& result) { auto primitive = __vwsn::UnboxWeak>(value); if (primitive) { result = CreateUnknownTuple(keyword, CreateJsonNumber(__vwsn::ToString(primitive.Value()))); return true; } return false; } template bool TrySerializeStringPrimitive(const Value& value, const WString& keyword, Ptr& result) { auto primitive = __vwsn::UnboxWeak>(value); if (primitive) { result = CreateUnknownTuple(keyword, CreateJsonString(__vwsn::ToString(primitive.Value()))); return true; } return false; } Ptr SerializeCollection(const WString& keyword, Ptr 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(object); } Ptr SerializeMap(Ptr 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(object); } Ptr TrySerializeCollectionTypes(const Value& value, const RpcJsonSerializeCallback& rpcjson_Serialize) { if (auto observableList = __vwsn::UnboxWeak>(value)) { return SerializeCollection(WString::Unmanaged(L"oblist"), observableList, rpcjson_Serialize); } if (auto dictionary = __vwsn::UnboxWeak>(value)) { return SerializeMap(dictionary, rpcjson_Serialize); } if (auto readonlyDictionary = __vwsn::UnboxWeak>(value)) { return SerializeMap(readonlyDictionary, rpcjson_Serialize); } if (auto list = __vwsn::UnboxWeak>(value)) { return SerializeCollection(WString::Unmanaged(L"list"), list, rpcjson_Serialize); } if (auto readonlyList = __vwsn::UnboxWeak>(value)) { return SerializeCollection(WString::Unmanaged(L"list"), readonlyList, rpcjson_Serialize); } if (auto enumerable = __vwsn::UnboxWeak>(value)) { return SerializeCollection(WString::Unmanaged(L"list"), enumerable, rpcjson_Serialize); } return nullptr; } Ptr TrySerializeRpcTypes(const Value& value) { if (auto ref = __vwsn::UnboxWeak>(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(object); } if (auto exception = __vwsn::UnboxWeak>(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(object); } return nullptr; } Value DeserializeList(Ptr object, bool observable, const RpcJsonDeserializeCallback& rpcjson_Deserialize) { auto values = GetJsonObjectField(object, WString::Unmanaged(L"values")).Cast(); 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 object, const RpcJsonDeserializeCallback& rpcjson_Deserialize) { auto values = GetJsonObjectField(object, WString::Unmanaged(L"values")).Cast(); CHECK_ERROR(values, L"JSON array is expected."); auto result = IValueDictionary::Create(); for (auto item : values->items) { auto pair = item.Cast(); 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 object, const WString& keyword) { if (keyword == L"system::RpcObjectReference") { return BoxValue(RpcObjectReference{ __vwsn::Parse(GetJsonNumber(GetJsonObjectField(object, WString::Unmanaged(L"clientId")))), __vwsn::Parse(GetJsonNumber(GetJsonObjectField(object, WString::Unmanaged(L"objectId")))), __vwsn::Parse(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 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 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 ValueToJsonNode(const Value& value) { if (value.GetValueType() == Value::SharedPtr) { if (auto node = value.GetSharedPtr().Cast()) { return node; } } CHECK_FAIL(L"RPC JSON value should be a Ptr."); return nullptr; } Ptr ValueArrayToJsonArray(Ptr arguments) { auto array = CreateJsonArray(); for (vint i = 0; i < arguments->GetCount(); i++) { array->items.Add(ValueToJsonNode(arguments->Get(i))); } return array; } Ptr JsonArrayToValueArray(Ptr 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 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 object) { return GetJsonInt(GetJsonObjectField(object, WString::Unmanaged(L"sourceClientId"))); } vint ReadTargetClientId(Ptr 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 MethodResultToJsonResponse(const Value& result) { if (result.GetValueType() == Value::SharedPtr) { if (auto byvalReturnValue = result.GetSharedPtr().Cast()) { 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 node) { if (auto object = node.Cast()) { 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 SerializePredefinedValue(const Value& value) { RpcJsonSerializeCallback rpcjson_Serialize; rpcjson_Serialize = Func(const Value&)>([&rpcjson_Serialize](const Value& item) { return JsonSerializePredefinedTypes(item, rpcjson_Serialize); }); return JsonSerializePredefinedTypes(value, rpcjson_Serialize); } Value DeserializePredefinedValue(Ptr node) { RpcJsonDeserializeCallback rpcjson_Deserialize; rpcjson_Deserialize = Func)>([&rpcjson_Deserialize](Ptr item) { return JsonDeserializePredefinedTypes(BoxValue(item), rpcjson_Deserialize); }); return JsonDeserializePredefinedTypes(BoxValue(node), rpcjson_Deserialize); } Ptr CreatePlainRpcException(const RpcException& exception) { auto result = CreateJsonObject(); AddJsonObjectField(result, WString::Unmanaged(L"message"), CreateJsonString(exception.message)); return result; } RpcException ReadPlainRpcException(Ptr node) { auto object = GetJsonObject(node); return { GetJsonString(GetJsonObjectField(object, WString::Unmanaged(L"message"))) }; } Ptr CreateEventExceptionResponse(Ptr serialized) { auto value = DeserializePredefinedValue(serialized); if (value.IsNull()) { return CreateJsonLiteral(JsonLiteralValue::Null); } auto exceptions = UnboxValue(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(key))); resultPair->items.Add(CreatePlainRpcException(UnboxValue(exceptions->Get(key)))); result->items.Add(resultPair); } return result; } Ptr CreateSerializedEventExceptionMap(Ptr response) { if (auto literal = response.Cast()) { 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 JsonSerializePredefinedTypes(const Value& value, const RpcJsonSerializeCallback& rpcjson_Serialize) { if (value.IsNull()) { return CreateJsonLiteral(JsonLiteralValue::Null); } if (auto primitive = __vwsn::UnboxWeak>(value)) { return CreateJsonLiteral(primitive.Value() ? JsonLiteralValue::True : JsonLiteralValue::False); } if (auto primitive = __vwsn::UnboxWeak>(value)) { return CreateJsonString(primitive.Value()); } Ptr result; if (TrySerializeNumberPrimitive(value, WString::Unmanaged(L"UInt8"), result)) return result; if (TrySerializeNumberPrimitive(value, WString::Unmanaged(L"UInt16"), result)) return result; if (TrySerializeNumberPrimitive(value, WString::Unmanaged(L"UInt32"), result)) return result; if (TrySerializeNumberPrimitive(value, WString::Unmanaged(L"UInt64"), result)) return result; if (TrySerializeNumberPrimitive(value, WString::Unmanaged(L"Int8"), result)) return result; if (TrySerializeNumberPrimitive(value, WString::Unmanaged(L"Int16"), result)) return result; if (TrySerializeNumberPrimitive(value, WString::Unmanaged(L"Int32"), result)) return result; if (TrySerializeNumberPrimitive(value, WString::Unmanaged(L"Int64"), result)) return result; if (TrySerializeNumberPrimitive(value, WString::Unmanaged(L"Single"), result)) return result; if (TrySerializeNumberPrimitive(value, WString::Unmanaged(L"Double"), result)) return result; if (TrySerializeStringPrimitive(value, WString::Unmanaged(L"Char"), result)) return result; if (TrySerializeStringPrimitive(value, WString::Unmanaged(L"DateTime"), result)) return result; if (TrySerializeStringPrimitive(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>(value); if (!node) { return {}; } if (auto literal = node.Cast()) { 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()) { return BoxValue(stringNode->content.value); } if (auto numberNode = node.Cast()) { return BoxValue(numberNode->content.value); } if (auto array = node.Cast()) { if (array->items.Count() == 2) { if (auto keywordNode = array->items[0].Cast()) { auto keyword = keywordNode->content.value; auto item = array->items[1]; if (keyword == L"UInt8") return BoxValue(__vwsn::Parse(GetJsonNumber(item))); if (keyword == L"UInt16") return BoxValue(__vwsn::Parse(GetJsonNumber(item))); if (keyword == L"UInt32") return BoxValue(__vwsn::Parse(GetJsonNumber(item))); if (keyword == L"UInt64") return BoxValue(__vwsn::Parse(GetJsonNumber(item))); if (keyword == L"Int8") return BoxValue(__vwsn::Parse(GetJsonNumber(item))); if (keyword == L"Int16") return BoxValue(__vwsn::Parse(GetJsonNumber(item))); if (keyword == L"Int32") return BoxValue(__vwsn::Parse(GetJsonNumber(item))); if (keyword == L"Int64") return BoxValue(__vwsn::Parse(GetJsonNumber(item))); if (keyword == L"Single") return BoxValue(__vwsn::Parse(GetJsonNumber(item))); if (keyword == L"Double") return BoxValue(__vwsn::Parse(GetJsonNumber(item))); if (keyword == L"Char") return BoxValue(__vwsn::Parse(GetJsonString(item))); if (keyword == L"DateTime") return BoxValue(__vwsn::Parse(GetJsonString(item))); if (keyword == L"Locale") return BoxValue(__vwsn::Parse(GetJsonString(item))); } } auto result = IValueList::Create(); for (auto item : array->items) { result->Add(rpcjson_Deserialize(item)); } return BoxValue(result); } if (auto object = node.Cast()) { 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 IRpcJsonMessageDispatcher::DefaultTranslate( Ptr message, RequestType requestType, IRpcObjectOps* objectOps, IRpcObjectEventOps* objectEventOps, IRpcDispatcher* dispatcher, IRpcLifecycle* lifecycle ) { #define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::IRpcJsonMessageDispatcher::DefaultTranslate(Ptr, 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 arguments) { #define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonObjectOps::InvokeMethod(RpcObjectReference, vint, Ptr)#" 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 RpcJsonObjectOps::Translate(Ptr message, IRpcObjectOps* ops, IRpcLifecycle* lifecycle) { #define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonObjectOps::Translate(Ptr, 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 arguments) { #define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonObjectEventOps::InvokeEvent(RpcObjectReference, vint, Ptr)#" 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 RpcJsonObjectEventOps::Translate(Ptr message, IRpcObjectEventOps* ops, IRpcLifecycle* lifecycle) { #define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonObjectEventOps::Translate(Ptr, 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 RpcJsonDispatcher::Translate(Ptr message, IRpcDispatcher* dispatcher, IRpcLifecycle* lifecycle) { #define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonDispatcher::Translate(Ptr, 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 _serializer, Ptr _objectOps, Ptr _objectEventOps, Func _getTypeId, Func _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 message) { return GetJsonInt(GetJsonObjectField(GetJsonObject(message), WString::Unmanaged(L"rpcRequestId"))); } void WriteRequestId(Ptr message, vint requestId) { SetJsonObjectField(GetJsonObject(message), WString::Unmanaged(L"rpcRequestId"), CreateJsonNumber(requestId)); } } } /*********************************************************************** .\RPCJSON\WFLIBRARYRPCJSONDISPATCHERCLIENT.CPP ***********************************************************************/ #include 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 CreateJsonString(const WString& value) { auto node = Ptr(new JsonString); node->content.value = value; return node; } Ptr CreateJsonNumber(vint value) { auto node = Ptr(new JsonNumber); node->content.value = itow(value); return node; } Ptr CreateJsonObject() { return Ptr(new JsonObject); } Ptr GetJsonObject(Ptr node) { auto object = node.Cast(); CHECK_ERROR(object, L"RpcJsonDispatcherClient expects a JSON object."); return object; } void AddJsonObjectField(Ptr object, const WString& name, Ptr value) { auto field = Ptr(new JsonObjectField); field->name.value = name; field->value = value; object->fields.Add(field); } void SetJsonObjectField(Ptr object, const WString& name, Ptr value) { for (auto field : object->fields) { if (field->name.value == name) { field->value = value; return; } } AddJsonObjectField(object, name, value); } Ptr FindJsonObjectField(Ptr object, const WString& name) { for (auto field : object->fields) { if (field->name.value == name) { return field->value; } } return nullptr; } Ptr GetJsonObjectField(Ptr object, const WString& name) { auto field = FindJsonObjectField(object, name); CHECK_ERROR(field, L"RpcJsonDispatcherClient expects a JSON object field."); return field; } WString GetJsonString(Ptr node) { auto stringNode = node.Cast(); CHECK_ERROR(stringNode, L"RpcJsonDispatcherClient expects a JSON string."); return stringNode->content.value; } vint GetJsonInt(Ptr node) { auto numberNode = node.Cast(); 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 message) { if (auto object = message.Cast()) { if (auto field = FindJsonObjectField(object, WString::Unmanaged(L"rpcMethod"))) { if (auto stringNode = field.Cast()) { 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 message) { return GetJsonInt(GetJsonObjectField(GetJsonObject(message), WString::Unmanaged(L"rpcRequestId"))); } vint ReadTargetClientId(Ptr message) { return GetJsonInt(GetJsonObjectField(GetJsonObject(message), WString::Unmanaged(L"targetClientId"))); } vint ReadDeclaredServiceTypeId(Ptr message) { auto ref = GetJsonObject(GetJsonObjectField(GetJsonObject(message), WString::Unmanaged(L"ref"))); return GetJsonInt(GetJsonObjectField(ref, WString::Unmanaged(L"typeId"))); } Ptr 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 CreateLogoutMessage() { auto message = CreateJsonObject(); AddJsonObjectField(message, WString::Unmanaged(L"rpcChannelingSystem"), CreateJsonString(WString::Unmanaged(L"Logout"))); return message; } bool TryReadLoginMessage(Ptr message, vint& serverClientId) { if (auto object = message.Cast()) { 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& _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 _rpcDispatcher, Ptr _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 cached; SPIN_LOCK(lockServiceDeclarations) { for (auto request : cachedIncomingServiceDeclarations) { cached.Add(request); } cachedIncomingServiceDeclarations.Clear(); } for (auto request : cached) { ProcessIncomingServiceDeclaration(request); } } void RpcJsonDispatcherClient::SendCachedOutgoingServiceDeclarations() { List 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& _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 localClient, JsonChannel* channel, const List& _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([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 task) { taskQueue->QueueTask(task); } RpcJsonDispatcherClientForTaskQueue::RpcJsonDispatcherClientForTaskQueue(Ptr _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 ServerCreateJsonLiteral(JsonLiteralValue value) { auto node = Ptr(new JsonLiteral); node->value = value; return node; } Ptr ServerCreateJsonString(const WString& value) { auto node = Ptr(new JsonString); node->content.value = value; return node; } Ptr ServerCreateJsonNumber(vint value) { auto node = Ptr(new JsonNumber); node->content.value = itow(value); return node; } Ptr ServerCreateJsonArray() { return Ptr(new JsonArray); } Ptr ServerCreateJsonObject() { return Ptr(new JsonObject); } Ptr ServerGetJsonObject(Ptr node) { auto object = node.Cast(); CHECK_ERROR(object, L"RpcJsonDispatcherServer expects a JSON object."); return object; } Ptr ServerGetJsonArray(Ptr node) { auto array = node.Cast(); CHECK_ERROR(array, L"RpcJsonDispatcherServer expects a JSON array."); return array; } void ServerAddJsonObjectField(Ptr object, const WString& name, Ptr value) { auto field = Ptr(new JsonObjectField); field->name.value = name; field->value = value; object->fields.Add(field); } void ServerSetJsonObjectField(Ptr object, const WString& name, Ptr value) { for (auto field : object->fields) { if (field->name.value == name) { field->value = value; return; } } ServerAddJsonObjectField(object, name, value); } Ptr ServerFindJsonObjectField(Ptr object, const WString& name) { for (auto field : object->fields) { if (field->name.value == name) { return field->value; } } return nullptr; } Ptr ServerGetJsonObjectField(Ptr object, const WString& name) { auto field = ServerFindJsonObjectField(object, name); CHECK_ERROR(field, L"RpcJsonDispatcherServer expects a JSON object field."); return field; } WString ServerGetJsonString(Ptr node) { auto stringNode = node.Cast(); CHECK_ERROR(stringNode, L"RpcJsonDispatcherServer expects a JSON string."); return stringNode->content.value; } vint ServerGetJsonInt(Ptr node) { auto numberNode = node.Cast(); CHECK_ERROR(numberNode, L"RpcJsonDispatcherServer expects a JSON number."); return wtoi(numberNode->content.value); } bool ServerIsJsonNull(Ptr node) { auto literal = node.Cast(); 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 message) { if (auto object = message.Cast()) { if (auto field = ServerFindJsonObjectField(object, WString::Unmanaged(L"rpcMethod"))) { if (auto stringNode = field.Cast()) { 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 message) { return ServerGetJsonInt(ServerGetJsonObjectField(ServerGetJsonObject(message), WString::Unmanaged(L"rpcRequestId"))); } void ServerWriteRequestId(Ptr message, vint requestId) { ServerSetJsonObjectField(ServerGetJsonObject(message), WString::Unmanaged(L"rpcRequestId"), ServerCreateJsonNumber(requestId)); } vint ServerReadSourceClientId(Ptr message) { return ServerGetJsonInt(ServerGetJsonObjectField(ServerGetJsonObject(message), WString::Unmanaged(L"sourceClientId"))); } void ServerWriteSourceClientId(Ptr message, vint clientId) { ServerSetJsonObjectField(ServerGetJsonObject(message), WString::Unmanaged(L"sourceClientId"), ServerCreateJsonNumber(clientId)); } Ptr 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 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 message) { if (auto object = message.Cast()) { auto systemField = ServerFindJsonObjectField(object, WString::Unmanaged(L"rpcChannelingSystem")); return systemField && ServerGetJsonString(systemField) == WString::Unmanaged(L"Logout"); } return false; } bool ServerIsBroadcastReady(Ptr 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 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 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 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 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([this, clientId]() { SendLoginMessages(clientId); })); } void RpcJsonDispatcherServer::DisconnectClient(vint clientId) { if (clientId == GetServerClientId()) { return; } List 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 task) { taskQueue->QueueTask(task); } RpcJsonDispatcherServerForTaskQueue::RpcJsonDispatcherServerForTaskQueue(JsonChannelClient* _serverClient, JsonChannel* channel, Ptr _taskQueue) : RpcJsonDispatcherServer(_serverClient, channel) , taskQueue(_taskQueue) { CHECK_ERROR(taskQueue, L"RpcJsonDispatcherServerForTaskQueue needs a task queue."); } }