diff --git a/desktop/addons/windows-pushnotifications/CollectionsConverter.h b/desktop/addons/windows-pushnotifications/CollectionsConverter.h new file mode 100644 --- /dev/null +++ b/desktop/addons/windows-pushnotifications/CollectionsConverter.h @@ -0,0 +1,305 @@ +// Copyright (c) The NodeRT Contributors +// All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the ""License""); you may +// not use this file except in compliance with the License. You may obtain a +// copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS +// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY +// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +// MERCHANTABLITY OR NON-INFRINGEMENT. +// +// See the Apache Version 2.0 License for specific language governing +// permissions and limitations under the License. + +#pragma once +#include +#include +#include "CollectionsConverterUtils.h" +#include "NodeRtUtils.h" +#include "nan.h" + +namespace NodeRT +{ + namespace Collections + { + + Nan::Persistent g_keyProp; + Nan::Persistent g_valueProp; + + static void initProps() + { + if (g_keyProp.IsEmpty()) + g_keyProp.Reset(Nan::New("key").ToLocalChecked()); + + if (g_valueProp.IsEmpty()) + g_valueProp.Reset(Nan::New("value").ToLocalChecked()); + } + + static std::function)> checkStringFunc = + [](v8::Local value) -> bool + { return value->IsString(); }; + + template + static ::Platform::Collections::Map ^ + JsArrayToWinrtMap( + v8::Local arr, + const std::function)> &checkKeyTypeFunc, + const std::function)> &convertToKeyTypeFunc, + const std::function)> &checkValueTypeFunc, + const std::function)> &convertToValueTypeFunc) { + std::map stdMap; + if (!FillMapFromJsArray(arr, checkKeyTypeFunc, convertToKeyTypeFunc, + checkValueTypeFunc, convertToValueTypeFunc, + stdMap)) + { + return nullptr; + } + + // TODO: michfa: consider using std::move (here & everywhere), e.g: return + // ref new ::Platform::Collections::Map(std::move(stdMap)); + // std::move will give a more efficient initialization from std::map, will + // invalidate stdMap however- some types will throw while moving + return ref new ::Platform::Collections::Map(stdMap); + } + + template + static ::Platform::Collections::MapView ^ + JsArrayToWinrtMapView( + v8::Local arr, + const std::function)> &checkKeyTypeFunc, + const std::function)> &convertToKeyTypeFunc, + const std::function)> &checkValueTypeFunc, + const std::function)> &convertToValueTypeFunc) { + std::map stdMap; + if (!FillMapFromJsArray(arr, checkKeyTypeFunc, convertToKeyTypeFunc, + checkValueTypeFunc, convertToValueTypeFunc, + stdMap)) + { + return nullptr; + } + + return ref new ::Platform::Collections::MapView(stdMap); + } + + // A special implementation for the case were the map's keys are strings + // In this case we expect a non-array JS object. + template + static ::Platform::Collections::Map ^ + JsObjectToWinrtMap( + v8::Local obj, + const std::function)> &checkValueTypeFunc, + const std::function)> &convertToValueTypeFunc) { + std::map<::Platform::String ^, V> stdMap; + + if (!FillMapFromJsObject( + obj, checkStringFunc, NodeRT::Utils::V8StringToPlatformString, + checkValueTypeFunc, convertToValueTypeFunc, stdMap)) + { + return nullptr; + } + + return ref new ::Platform::Collections::Map<::Platform::String ^, V>( + stdMap); + } + + template + static ::Platform::Collections::MapView ^ + JsObjectToWinrtMapView( + v8::Local obj, + const std::function)> &checkValueTypeFunc, + const std::function)> &convertToValueTypeFunc) { + std::map<::Platform::String ^, V> stdMap; + if (!FillMapFromJsObject( + obj, checkStringFunc, NodeRT::Utils::V8StringToPlatformString, + checkValueTypeFunc, convertToValueTypeFunc, stdMap)) + { + return nullptr; + } + + return ref new ::Platform::Collections::MapView<::Platform::String ^, V>( + stdMap); + } + + template + static ::Platform::Collections::Vector ^ + JsArrayToWinrtVector( + v8::Local arr, + const std::function)> &checkValueTypeFunc, + const std::function)> &convertToValueTypeFunc) { + std::vector vec(arr->Length()); + if (!FillVector &, V>(arr, checkValueTypeFunc, + convertToValueTypeFunc, vec)) + { + return nullptr; + } + + return ref new ::Platform::Collections::Vector(vec); + } + + template + static ::Platform::Collections::VectorView ^ + JsArrayToWinrtVectorView( + v8::Local arr, + const std::function)> &checkValueTypeFunc, + const std::function)> &convertToValueTypeFunc) { + std::vector vec(arr->Length()); + + if (!FillVector &, V>(arr, checkValueTypeFunc, + convertToValueTypeFunc, vec)) + { + return nullptr; + } + + return ref new ::Platform::Collections::VectorView(vec); + } + + template + static ::Platform::Array ^ + JsArrayToWinrtArray( + v8::Local arr, + const std::function)> &checkValueTypeFunc, + const std::function)> &convertToValueTypeFunc) { + auto vec = ref new ::Platform::Array(arr->Length()); + if (!FillVector<::Platform::Array ^, V>(arr, checkValueTypeFunc, + convertToValueTypeFunc, vec)) + { + return nullptr; + } + + return vec; + } + } // namespace Collections + + template + static void InsertToVector( + uint32_t index, + v8::Local value, + const std::function)> &convertToValueTypeFunc, + std::vector &vec) + { + vec[index] = convertToValueTypeFunc(value); + } + + template + static void InsertToVector( + uint32_t index, + v8::Local value, + const std::function)> &convertToValueTypeFunc, + ::Platform::Array ^ vec) + { + vec->set(index, convertToValueTypeFunc(value)); + } + + // assumption: vec length >= arr length + template + static bool FillVector( + v8::Local arr, + const std::function)> &checkValueTypeFunc, + const std::function)> &convertToValueTypeFunc, + T vec) + { + for (uint32_t i = 0; i < arr->Length(); i++) + { + Local value = Nan::Get(arr, i).ToLocalChecked(); + + if (!checkValueTypeFunc(value)) + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"Received array with unexpected value type"))); + return false; + } + + InsertToVector(i, value, convertToValueTypeFunc, vec); + } + + return true; + } + + template + static bool FillMapFromJsArray( + v8::Local arr, + const std::function)> &checkKeyTypeFunc, + const std::function)> &convertToKeyTypeFunc, + const std::function)> &checkValueTypeFunc, + const std::function)> &convertToValueTypeFunc, + std::map &stdMap) + { + initProps(); + + // expect that each element in the array will be an object with 2 properties: + // key and value (with types that match K and V respectively) + for (uint32_t i = 0; i < arr->Length(); i++) + { + Local curr = Nan::Get(arr, i).ToLocalChecked(); + + if (!curr->IsObject()) + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"Array elements are expected to be javascript objects"))); + return false; + } + + v8::Local obj = curr.As(); + + if (!obj->Has(g_keyProp) || !obj->Has(g_valueProp)) + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"Array elements are expected to be javascript objects with \'key\' " + L"and \'value\' properties"))); + return false; + } + + Local key = Nan::Get(obj, g_keyProp).ToLocalChecked(); + Local value = Nan::Get(obj, g_valueProp).ToLocalChecked(); + + if (!checkKeyTypeFunc(key)) + { + Nan::ThrowError(Nan::Error( + NodeRT::Utils::NewString(L"Array element has invalid key type"))); + return false; + } + + if (!checkValueTypeFunc(value)) + { + Nan::ThrowError(Nan::Error( + NodeRT::Utils::NewString(L"Array element has invalid value type"))); + return false; + } + + stdMap.insert(std::pair(convertToKeyTypeFunc(key), + convertToValueTypeFunc(value))); + } + + return true; + } + + template + static bool FillMapFromJsObject( + v8::Local obj, + const std::function)> &checkKeyTypeFunc, + const std::function<::Platform::String ^ (v8::Local)> & + convertToKeyTypeFunc, + const std::function)> &checkValueTypeFunc, + const std::function)> &convertToValueTypeFunc, + std::map<::Platform::String ^, V> &stdMap) + { + Local objProps = Nan::GetPropertyNames(obj).ToLocalChecked(); + for (uint32_t i = 0; i < objProps->Length(); i++) + { + Local key = Nan::Get(objProps, i).ToLocalChecked(); + Local value = Nan::Get(obj, key).ToLocalChecked(); + if (!checkValueTypeFunc(value)) + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"Received object with unexpected value type"))); + return false; + } + + stdMap.insert(std::pair<::Platform::String ^, V>( + convertToKeyTypeFunc(key), convertToValueTypeFunc(value))); + } + return true; + } +}; // namespace NodeRT diff --git a/desktop/addons/windows-pushnotifications/CollectionsConverterUtils.h b/desktop/addons/windows-pushnotifications/CollectionsConverterUtils.h new file mode 100644 --- /dev/null +++ b/desktop/addons/windows-pushnotifications/CollectionsConverterUtils.h @@ -0,0 +1,38 @@ +// Copyright (c) The NodeRT Contributors +// All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the ""License""); you may +// not use this file except in compliance with the License. You may obtain a +// copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS +// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY +// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +// MERCHANTABLITY OR NON-INFRINGEMENT. +// +// See the Apache Version 2.0 License for specific language governing +// permissions and limitations under the License. + +#pragma once + +// Every type used in Vector or VectorView template instantiation must have +// operator== Implement operator== for types that don't have an operator== +// implementation available and there is no acceptable conversion to an existing +// operator== +namespace std +{ + + bool operator==(const ::Windows::Foundation::TimeSpan &first, + const ::Windows::Foundation::TimeSpan &second); + + bool operator==( + const ::Windows::Devices::Geolocation::BasicGeoposition &first, + const ::Windows::Devices::Geolocation::BasicGeoposition &second); + + bool operator==(const ::Windows::Storage::Search::SortEntry &first, + const ::Windows::Storage::Search::SortEntry &second); + + bool operator==(const ::Windows::Data::Text::TextSegment &first, + const ::Windows::Data::Text::TextSegment &second); + +} // namespace std diff --git a/desktop/addons/windows-pushnotifications/CollectionsConverterUtils.cpp b/desktop/addons/windows-pushnotifications/CollectionsConverterUtils.cpp new file mode 100644 --- /dev/null +++ b/desktop/addons/windows-pushnotifications/CollectionsConverterUtils.cpp @@ -0,0 +1,49 @@ +// Copyright (c) The NodeRT Contributors +// All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the ""License""); you may +// not use this file except in compliance with the License. You may obtain a +// copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS +// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY +// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +// MERCHANTABLITY OR NON-INFRINGEMENT. +// +// See the Apache Version 2.0 License for specific language governing +// permissions and limitations under the License. + +#include "CollectionsConverterUtils.h" + +namespace std +{ + bool operator==(const ::Windows::Foundation::TimeSpan &first, + const ::Windows::Foundation::TimeSpan &second) + { + return first.Duration == second.Duration; + } + + bool operator==( + const ::Windows::Devices::Geolocation::BasicGeoposition &first, + const ::Windows::Devices::Geolocation::BasicGeoposition &second) + { + return (first.Altitude == second.Altitude) && + (first.Latitude == second.Latitude) && + (first.Longitude == second.Longitude); + } + + bool operator==(const ::Windows::Storage::Search::SortEntry &first, + const ::Windows::Storage::Search::SortEntry &second) + { + return (first.AscendingOrder == second.AscendingOrder) && + (first.PropertyName == second.PropertyName); + } + + bool operator==(const ::Windows::Data::Text::TextSegment &first, + const ::Windows::Data::Text::TextSegment &second) + { + return (first.Length == second.Length) && + (first.StartPosition == second.StartPosition); + } + +} // namespace std diff --git a/desktop/addons/windows-pushnotifications/CollectionsWrap.h b/desktop/addons/windows-pushnotifications/CollectionsWrap.h new file mode 100644 --- /dev/null +++ b/desktop/addons/windows-pushnotifications/CollectionsWrap.h @@ -0,0 +1,2363 @@ +// Copyright (c) The NodeRT Contributors +// All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the ""License""); you may +// not use this file except in compliance with the License. You may obtain a +// copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS +// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY +// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +// MERCHANTABLITY OR NON-INFRINGEMENT. +// +// See the Apache Version 2.0 License for specific language governing +// permissions and limitations under the License. +#pragma once + +#include +#include "NodeRtUtils.h" +#include "OpaqueWrapper.h" +#include "WrapperBase.h" +#include "nan.h" + +#include + +namespace NodeRT +{ + namespace Collections + { + + using Nan::False; + using Nan::HandleScope; + using Nan::MaybeLocal; + using Nan::Null; + using Nan::Persistent; + using Nan::True; + using Nan::Undefined; + using v8::Boolean; + using v8::FunctionTemplate; + using v8::Integer; + using v8::Local; + using v8::String; + using v8::Value; + + template + class ArrayWrapper : NodeRT::WrapperBase + { + public: + static void Init() + { + EscapableHandleScope scope; + + Local localRef = Nan::New(New); + s_constructorTemplate.Reset(localRef); + + localRef->SetClassName( + Nan::New("Windows::Foundation::Array").ToLocalChecked()); + localRef->InstanceTemplate()->SetInternalFieldCount(1); + Nan::SetIndexedPropertyHandler(localRef->InstanceTemplate(), Get, Set); + + Nan::SetAccessor(localRef->PrototypeTemplate(), + Nan::New("length").ToLocalChecked(), LengthGetter); + + return; + } + + static Local CreateArrayWrapper( + ::Platform::Array ^ winRtInstance, + const std::function(T)> &getterFunc = nullptr, + const std::function)> &checkTypeFunc = nullptr, + const std::function)> &convertToTypeFunc = nullptr) + { + EscapableHandleScope scope; + if (winRtInstance == nullptr) + { + return scope.Escape(Undefined()); + } + + if (s_constructorTemplate.IsEmpty()) + { + Init(); + } + + v8::Local args[] = {Undefined()}; + Local localRef = + Nan::New(s_constructorTemplate); + Local objectInstance = + Nan::NewInstance(Nan::GetFunction(localRef).ToLocalChecked(), 0, args) + .ToLocalChecked(); + if (objectInstance.IsEmpty()) + { + return scope.Escape(Undefined()); + } + + ArrayWrapper *wrapperInstance = new ArrayWrapper( + winRtInstance, getterFunc, checkTypeFunc, convertToTypeFunc); + wrapperInstance->Wrap(objectInstance); + return scope.Escape(objectInstance); + } + + virtual ::Platform::Object ^ GetObjectInstance() const override + { + return _instance; + } + + private: + ArrayWrapper( + ::Platform::Array ^ winRtInstance, + const std::function(T)> &getterFunc, + const std::function)> &checkTypeFunc = nullptr, + const std::function)> &convertToTypeFunc = nullptr) + : _instance(winRtInstance), + _getterFunc(getterFunc), + _checkTypeFunc(checkTypeFunc), + _convertToTypeFunc(convertToTypeFunc) {} + + static void New(Nan::NAN_METHOD_ARGS_TYPE info) + { + NodeRT::Utils::SetHiddenValue( + info.This(), Nan::New("__winRtInstance__").ToLocalChecked(), + True()); + + info.GetReturnValue().Set(info.This()); + } + + static void LengthGetter(Local property, + const Nan::PropertyCallbackInfo &info) + { + HandleScope scope; + if (!NodeRT::Utils::IsWinRtWrapperOf<::Platform::Array ^>(info.This())) + { + return; + } + + ArrayWrapper *wrapper = + ArrayWrapper::Unwrap>(info.This()); + + try + { + unsigned int result = wrapper->_instance->Length; + info.GetReturnValue().Set(Nan::New(result)); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + + static void Get(uint32_t index, + const Nan::PropertyCallbackInfo &info) + { + HandleScope scope; + if (!NodeRT::Utils::IsWinRtWrapperOf<::Platform::Array ^>(info.This())) + { + return; + } + + ArrayWrapper *wrapper = + ArrayWrapper::Unwrap>(info.This()); + + if (wrapper->_instance->Length <= index) + { + return; + } + + if (wrapper->_getterFunc == nullptr) + { + info.GetReturnValue().Set(CreateOpaqueWrapper(wrapper->_instance[index])); + } + else + { + info.GetReturnValue().Set( + wrapper->_getterFunc(wrapper->_instance[index])); + } + } + + static void Set(uint32_t index, + Local value, + const Nan::PropertyCallbackInfo &info) + { + HandleScope scope; + if (!NodeRT::Utils::IsWinRtWrapperOf<::Platform::Array ^>(info.This())) + { + return; + } + + ArrayWrapper *wrapper = + ArrayWrapper::Unwrap>(info.This()); + + if (wrapper->_checkTypeFunc && !wrapper->_checkTypeFunc(value)) + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"The argument to set isn't of the expected type or internal WinRt " + L"object was disposed"))); + return; + } + + if (wrapper->_instance->Length <= index) + { + Nan::ThrowError(Nan::Error( + NodeRT::Utils::NewString(L"Given index exceeded array length"))); + return; + } + + if (wrapper->_convertToTypeFunc) + { + try + { + wrapper->_instance[index] = wrapper->_convertToTypeFunc(value); + } + catch (::Platform::Exception ^ e) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(e); + } + } + + return; + } + + private: + ::Platform::Array ^ _instance; + std::function(T)> _getterFunc; + std::function)> _checkTypeFunc; + std::function)> _convertToTypeFunc; + static Persistent s_constructorTemplate; + }; + + template + Persistent ArrayWrapper::s_constructorTemplate; + + template + class IteratorWrapper : NodeRT::WrapperBase + { + public: + static void Init() + { + HandleScope scope; + + Local localRef = Nan::New(New); + s_constructorTemplate.Reset(localRef); + localRef->SetClassName( + Nan::New("Windows::Foundation::Collections:IIterator") + .ToLocalChecked()); + localRef->InstanceTemplate()->SetInternalFieldCount(1); + + Nan::SetPrototypeMethod(localRef, "getMany", GetMany); + Nan::SetPrototypeMethod(localRef, "moveNext", MoveNext); + + Nan::SetAccessor(localRef->PrototypeTemplate(), + Nan::New("current").ToLocalChecked(), + CurrentGetter); + Nan::SetAccessor(localRef->PrototypeTemplate(), + Nan::New("hasCurrent").ToLocalChecked(), + HasCurrentGetter); + + return; + } + + static Local CreateIteratorWrapper( + ::Windows::Foundation::Collections::IIterator ^ winRtInstance, + const std::function(T)> &getterFunc = nullptr) + { + EscapableHandleScope scope; + if (winRtInstance == nullptr) + { + return scope.Escape(Undefined()); + } + + if (s_constructorTemplate.IsEmpty()) + { + Init(); + } + + v8::Local args[] = {Undefined()}; + Local localRef = + Nan::New(s_constructorTemplate); + Local objectInstance = + Nan::NewInstance(Nan::GetFunction(localRef).ToLocalChecked(), 0, args) + .ToLocalChecked(); + if (objectInstance.IsEmpty()) + { + return scope.Escape(Undefined()); + } + + IteratorWrapper *wrapperInstance = + new IteratorWrapper(winRtInstance, getterFunc); + wrapperInstance->Wrap(objectInstance); + return scope.Escape(objectInstance); + } + + virtual ::Platform::Object ^ GetObjectInstance() const override + { + return _instance; + } + + private: + IteratorWrapper(::Windows::Foundation::Collections::IIterator ^ + winRtInstance, + const std::function(T)> &getterFunc) + : _instance(winRtInstance), _getterFunc(getterFunc) {} + + static void New(Nan::NAN_METHOD_ARGS_TYPE info) + { + NodeRT::Utils::SetHiddenValue( + info.This(), Nan::New("__winRtInstance__").ToLocalChecked(), + True()); + info.GetReturnValue().Set(info.This()); + } + + static void MoveNext(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IIterator ^>(info.This())) + { + return; + } + + IteratorWrapper *wrapper = + IteratorWrapper::Unwrap>(info.This()); + + if (info.Length() == 0) + { + try + { + bool result; + result = wrapper->_instance->MoveNext(); + info.GetReturnValue().Set(Nan::New(result)); + return; + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"Bad arguments: no suitable overload found"))); + return; + } + } + + // Not supporting this for now since we need to initialize the array ourselves + // and don't know which size to use + static void GetMany(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString(L"Not implemented"))); + return; + } + + static void CurrentGetter(Local property, + const Nan::PropertyCallbackInfo &info) + { + HandleScope scope; + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IIterator ^>(info.This())) + { + return; + } + + IteratorWrapper *wrapper = + IteratorWrapper::Unwrap>(info.This()); + + try + { + T current = wrapper->_instance->Current; + + if (wrapper->_getterFunc != nullptr) + { + info.GetReturnValue().Set(wrapper->_getterFunc(current)); + } + else + { + info.GetReturnValue().Set(CreateOpaqueWrapper(current)); + } + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + + static void HasCurrentGetter( + Local property, + const Nan::PropertyCallbackInfo &info) + { + HandleScope scope; + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IIterator ^>(info.This())) + { + return; + } + + IteratorWrapper *wrapper = + IteratorWrapper::Unwrap>(info.This()); + + try + { + bool result = wrapper->_instance->HasCurrent; + info.GetReturnValue().Set(Nan::New(result)); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + + private: + ::Windows::Foundation::Collections::IIterator ^ _instance; + std::function(T)> _getterFunc; + static Persistent s_constructorTemplate; + }; + + template + class IterableWrapper : NodeRT::WrapperBase + { + public: + static void Init() + { + HandleScope scope; + + Local localRef = Nan::New(New); + s_constructorTemplate.Reset(localRef); + localRef->SetClassName( + Nan::New("Windows::Foundation::Collections:IIterable") + .ToLocalChecked()); + localRef->InstanceTemplate()->SetInternalFieldCount(1); + + Nan::SetPrototypeMethod(localRef, "first", First); + + return; + } + + static Local CreateIterableWrapper( + ::Windows::Foundation::Collections::IIterable ^ winRtInstance, + const std::function(T)> &getterFunc = nullptr) + { + EscapableHandleScope scope; + if (winRtInstance == nullptr) + { + return scope.Escape(Undefined()); + } + + if (s_constructorTemplate.IsEmpty()) + { + Init(); + } + + v8::Local args[] = {Undefined()}; + Local localRef = + Nan::New(s_constructorTemplate); + Local objectInstance = + Nan::NewInstance(Nan::GetFunction(localRef).ToLocalChecked(), 0, args) + .ToLocalChecked(); + + if (objectInstance.IsEmpty()) + { + return scope.Escape(Undefined()); + } + + IterableWrapper *wrapperInstance = + new IterableWrapper(winRtInstance, getterFunc); + wrapperInstance->Wrap(objectInstance); + return scope.Escape(objectInstance); + } + + virtual ::Platform::Object ^ GetObjectInstance() const override + { + return _instance; + } + + private: + IterableWrapper(::Windows::Foundation::Collections::IIterable ^ + winRtInstance, + const std::function(T)> &getterFunc) + : _instance(winRtInstance), _getterFunc(getterFunc) {} + + static void New(Nan::NAN_METHOD_ARGS_TYPE info) + { + NodeRT::Utils::SetHiddenValue( + info.This().Nan::New("__winRtInstance__").ToLocalChecked(), + True()); + info.GetReturnValue().Set(info.This()); + } + + static void First(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IIterable ^>(info.This())) + { + return; + } + + IterableWrapper *wrapper = + IterableWrapper::Unwrap>(info.This()); + + if (info.Length() == 0) + { + try + { + ::Windows::Foundation::Collections::IIterator ^ result = + wrapper->_instance->First(); + + info.GetReturnValue().Set(IteratorWrapper::CreateIteratorWrapper( + result, wrapper->_getterFunc)); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"Bad arguments: no suitable overload found"))); + return; + } + + return; + } + + private: + ::Windows::Foundation::Collections::IIterable ^ _instance; + std::function(T)> _getterFunc; + static Persistent s_constructorTemplate; + }; + + template + Persistent IterableWrapper::s_constructorTemplate; + + template + Persistent IteratorWrapper::s_constructorTemplate; + + template + class VectorViewWrapper : NodeRT::WrapperBase + { + public: + static void Init() + { + HandleScope scope; + + Local localRef = Nan::New(New); + s_constructorTemplate.Reset(localRef); + localRef->SetClassName( + Nan::New("Windows::Foundation::Collections:IVectorView") + .ToLocalChecked()); + localRef->InstanceTemplate()->SetInternalFieldCount(1); + Nan::SetIndexedPropertyHandler(localRef->InstanceTemplate(), Get); + + Nan::SetPrototypeMethod(localRef, "getMany", GetMany); + Nan::SetPrototypeMethod(localRef, "getAt", GetAt); + Nan::SetPrototypeMethod(localRef, "indexOf", IndexOf); + Nan::SetPrototypeMethod(localRef, "first", First); + + Nan::SetAccessor(localRef->PrototypeTemplate(), + Nan::New("size").ToLocalChecked(), SizeGetter); + Nan::SetAccessor(localRef->PrototypeTemplate(), + Nan::New("length").ToLocalChecked(), SizeGetter); + + return; + } + + static Local CreateVectorViewWrapper( + ::Windows::Foundation::Collections::IVectorView ^ winRtInstance, + const std::function(T)> &getterFunc, + const std::function)> &checkTypeFunc = nullptr, + const std::function)> &convertToTypeFunc = nullptr) + { + EscapableHandleScope scope; + if (winRtInstance == nullptr) + { + return scope.Escape(Undefined()); + } + + if (s_constructorTemplate.IsEmpty()) + { + Init(); + } + + v8::Local args[] = {Undefined()}; + Local localRef = + Nan::New(s_constructorTemplate); + Local objectInstance = + Nan::NewInstance(Nan::GetFunction(localRef).ToLocalChecked(), 0, args) + .ToLocalChecked(); + if (objectInstance.IsEmpty()) + { + return scope.Escape(Undefined()); + } + + VectorViewWrapper *wrapperInstance = + new VectorViewWrapper(winRtInstance, getterFunc); + wrapperInstance->Wrap(objectInstance); + return scope.Escape(objectInstance); + } + + virtual ::Platform::Object ^ GetObjectInstance() const override + { + return _instance; + } + + private: + VectorViewWrapper( + ::Windows::Foundation::Collections::IVectorView ^ winRtInstance, + const std::function(T)> &getterFunc, + const std::function)> &checkTypeFunc = nullptr, + const std::function)> &convertToTypeFunc = nullptr) + : _instance(winRtInstance), + _getterFunc(getterFunc), + _checkTypeFunc(checkTypeFunc), + _convertToTypeFunc(convertToTypeFunc) {} + + static void New(Nan::NAN_METHOD_ARGS_TYPE info) + { + NodeRT::Utils::SetHiddenValue( + info.This(), Nan::New("__winRtInstance__").ToLocalChecked(), + True()); + + info.GetReturnValue().Set(info.This()); + } + + static void Get(uint32_t index, + const Nan::PropertyCallbackInfo &info) + { + HandleScope scope; + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IVectorView ^>( + info.This())) + { + return; + } + + VectorViewWrapper *wrapper = + VectorViewWrapper::Unwrap>(info.This()); + + if (wrapper->_instance->Size <= index) + { + return; + } + + if (wrapper->_getterFunc == nullptr) + { + info.GetReturnValue().Set( + CreateOpaqueWrapper(wrapper->_instance->GetAt(index))); + } + else + { + info.GetReturnValue().Set( + wrapper->_getterFunc(wrapper->_instance->GetAt(index))); + } + } + + static void GetAt(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IVectorView ^>( + info.This())) + { + return; + } + + VectorViewWrapper *wrapper = + VectorViewWrapper::Unwrap>(info.This()); + + if (info.Length() == 1 && info[0]->IsUint32()) + { + try + { + unsigned int index = info[0]->Uint32Value(Nan::GetCurrentContext()).FromMaybe(0); + + if (index >= wrapper->_instance->Size) + { + return; + } + T result; + result = wrapper->_instance->GetAt(index); + + if (wrapper->_getterFunc) + { + info.GetReturnValue().Set(wrapper->_getterFunc(result)); + } + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"Bad arguments: no suitable overload found"))); + return; + } + + return; + } + + static void GetMany(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString(L"Not implemented"))); + return; + } + + static void First(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IVectorView ^>( + info.This())) + { + return; + } + + VectorViewWrapper *wrapper = + VectorViewWrapper::Unwrap>(info.This()); + + if (info.Length() == 0) + { + try + { + info.GetReturnValue().Set(IteratorWrapper::CreateIteratorWrapper( + wrapper->_instance->First(), wrapper->_getterFunc)); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"Bad arguments: no suitable overload found"))); + return; + } + + return; + } + + static void IndexOf(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IVectorView ^>( + info.This())) + { + return; + } + + VectorViewWrapper *wrapper = + VectorViewWrapper::Unwrap>(info.This()); + + if (wrapper->_convertToTypeFunc == nullptr || + wrapper->_checkTypeFunc == nullptr) + { + Nan::ThrowError( + Nan::Error(NodeRT::Utils::NewString(L"Method isn't supported"))); + return; + } + + if (info.Length() == 1 && wrapper->_checkTypeFunc(info[0])) + { + try + { + T item = wrapper->_convertToTypeFunc(info[0]); + + unsigned int index; + bool result = wrapper->_instance->IndexOf(item, &index); + + Local resObj = Nan::New(); + Nan::Set(resObj, Nan::New("boolean").ToLocalChecked(), + Nan::New(result)); + Nan::Set(resObj, Nan::New("index").ToLocalChecked(), + Nan::New(index)); + info.GetReturnValue().Set(resObj); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"Bad arguments: no suitable overload found"))); + return; + } + + return; + } + + static void SizeGetter(Local property, + const Nan::PropertyCallbackInfo &info) + { + HandleScope scope; + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IVectorView ^>( + info.This())) + { + return; + } + + VectorViewWrapper *wrapper = + VectorViewWrapper::Unwrap>(info.This()); + + try + { + info.GetReturnValue().Set(Nan::New(wrapper->_instance->Size)); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + + private: + ::Windows::Foundation::Collections::IVectorView ^ _instance; + std::function(T)> _getterFunc; + std::function)> _checkTypeFunc; + std::function)> _convertToTypeFunc; + static Persistent s_constructorTemplate; + }; + + template + Persistent VectorViewWrapper::s_constructorTemplate; + + template + class VectorWrapper : NodeRT::WrapperBase + { + public: + static void Init() + { + HandleScope scope; + + Local localRef = Nan::New(New); + s_constructorTemplate.Reset(localRef); + localRef->SetClassName( + Nan::New("Windows::Foundation::Collections:IVector") + .ToLocalChecked()); + localRef->InstanceTemplate()->SetInternalFieldCount(1); + Nan::SetIndexedPropertyHandler(localRef->InstanceTemplate(), Get, Set); + + Nan::SetPrototypeMethod(localRef, "getMany", GetMany); + Nan::SetPrototypeMethod(localRef, "getAt", GetAt); + Nan::SetPrototypeMethod(localRef, "indexOf", IndexOf); + Nan::SetPrototypeMethod(localRef, "first", First); + Nan::SetPrototypeMethod(localRef, "append", Append); + Nan::SetPrototypeMethod(localRef, "clear", Clear); + Nan::SetPrototypeMethod(localRef, "getView", GetView); + Nan::SetPrototypeMethod(localRef, "insertAt", InsertAt); + Nan::SetPrototypeMethod(localRef, "removeAt", RemoveAt); + Nan::SetPrototypeMethod(localRef, "removeAtEnd", RemoveAtEnd); + Nan::SetPrototypeMethod(localRef, "replaceAll", ReplaceAll); + Nan::SetPrototypeMethod(localRef, "setAt", SetAt); + + Nan::SetAccessor(localRef->PrototypeTemplate(), + Nan::New("size").ToLocalChecked(), SizeGetter); + Nan::SetAccessor(localRef->PrototypeTemplate(), + Nan::New("length").ToLocalChecked(), SizeGetter); + + return; + } + + static Local CreateVectorWrapper( + ::Windows::Foundation::Collections::IVector ^ winRtInstance, + const std::function(T)> &getterFunc, + const std::function)> &checkTypeFunc = nullptr, + const std::function)> &convertToTypeFunc = nullptr) + { + EscapableHandleScope scope; + if (winRtInstance == nullptr) + { + return scope.Escape(Undefined()); + } + + if (s_constructorTemplate.IsEmpty()) + { + Init(); + } + + v8::Local args[] = {Undefined()}; + Local localRef = + Nan::New(s_constructorTemplate); + Local objectInstance = + Nan::NewInstance(Nan::GetFunction(localRef).ToLocalChecked(), 0, args) + .ToLocalChecked(); + if (objectInstance.IsEmpty()) + { + return scope.Escape(Undefined()); + } + + VectorWrapper *wrapperInstance = new VectorWrapper( + winRtInstance, getterFunc, checkTypeFunc, convertToTypeFunc); + wrapperInstance->Wrap(objectInstance); + return scope.Escape(objectInstance); + } + + virtual ::Platform::Object ^ GetObjectInstance() const override + { + return _instance; + } + + private: + VectorWrapper( + ::Windows::Foundation::Collections::IVector ^ winRtInstance, + const std::function(T)> &getterFunc, + const std::function)> &checkTypeFunc = nullptr, + const std::function)> &convertToTypeFunc = nullptr) + : _instance(winRtInstance), + _getterFunc(getterFunc), + _checkTypeFunc(checkTypeFunc), + _convertToTypeFunc(convertToTypeFunc) {} + + static void New(Nan::NAN_METHOD_ARGS_TYPE info) + { + NodeRT::Utils::SetHiddenValue( + info.This(), Nan::New("__winRtInstance__").ToLocalChecked(), + True()); + + info.GetReturnValue().Set(info.This()); + } + + static void Get(uint32_t index, + const Nan::PropertyCallbackInfo &info) + { + HandleScope scope; + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IVector ^>(info.This())) + { + return; + } + + VectorWrapper *wrapper = + VectorWrapper::Unwrap>(info.This()); + + if (wrapper->_instance->Size <= index) + { + return; + } + + if (wrapper->_getterFunc == nullptr) + { + info.GetReturnValue().Set( + CreateOpaqueWrapper(wrapper->_instance->GetAt(index))); + } + else + { + info.GetReturnValue().Set( + wrapper->_getterFunc(wrapper->_instance->GetAt(index))); + } + } + + static void Set(uint32 index, + Local value, + const Nan::PropertyCallbackInfo &info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IVector ^>(info.This())) + { + return; + } + + VectorWrapper *wrapper = + VectorWrapper::Unwrap>(info.This()); + + if (!wrapper->_checkTypeFunc(value)) + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"The value to set isn't of the expected type"))); + return; + } + + try + { + T item = wrapper->_convertToTypeFunc(value); + + wrapper->_instance->SetAt(index, item); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + + return; + } + + static void Append(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IVector ^>(info.This())) + { + return; + } + + VectorWrapper *wrapper = + VectorWrapper::Unwrap>(info.This()); + + if (info.Length() == 1 && wrapper->_checkTypeFunc(info[0])) + { + try + { + T value = wrapper->_convertToTypeFunc(info[0]); + + wrapper->_instance->Append(value); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"Bad arguments: no suitable overload found"))); + return; + } + + return; + } + + static void Clear(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IVector ^>(info.This())) + { + return; + } + + VectorWrapper *wrapper = + VectorWrapper::Unwrap>(info.This()); + + if (info.Length() == 0) + { + try + { + wrapper->_instance->Clear(); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"Bad arguments: no suitable overload found"))); + return; + } + + return; + } + + static void GetMany(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString(L"Not implemented"))); + return; + } + + static void GetView(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IVector ^>(info.This())) + { + return; + } + + VectorWrapper *wrapper = + VectorWrapper::Unwrap>(info.This()); + + if (info.Length() == 0) + { + try + { + ::Windows::Foundation::Collections::IVectorView ^ result = + wrapper->_instance->GetView(); + info.GetReturnValue().Set(VectorViewWrapper::CreateVectorViewWrapper( + result, wrapper->_getterFunc, wrapper->_checkTypeFunc, + wrapper->_convertToTypeFunc)); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"Bad arguments: no suitable overload found"))); + return; + } + + return; + } + + static void InsertAt(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IVector ^>(info.This())) + { + return; + } + + VectorWrapper *wrapper = + VectorWrapper::Unwrap>(info.This()); + + if (info.Length() == 2 && info[0]->IsUint32() && + wrapper->_checkTypeFunc(info[1])) + { + try + { + unsigned int index = info[0]->Uint32Value(Nan::GetCurrentContext()).FromMaybe(0); + + T value = wrapper->_convertToTypeFunc(info[1]); + wrapper->_instance->InsertAt(index, value); + return; + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"Bad arguments: no suitable overload found"))); + return; + } + } + + static void RemoveAt(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IVector ^>(info.This())) + { + return; + } + + VectorWrapper *wrapper = + VectorWrapper::Unwrap>(info.This()); + + if (info.Length() == 1 && info[0]->IsUint32()) + { + try + { + unsigned int index = info[0]->Uint32Value(Nan::GetCurrentContext()).FromMaybe(0); + + wrapper->_instance->RemoveAt(index); + return; + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"Bad arguments: no suitable overload found"))); + return; + } + } + + static void RemoveAtEnd(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IVector ^>(info.This())) + { + return; + } + + VectorWrapper *wrapper = + VectorWrapper::Unwrap>(info.This()); + + if (info.Length() == 0) + { + try + { + wrapper->_instance->RemoveAtEnd(); + return; + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"Bad arguments: no suitable overload found"))); + return; + } + } + + static void ReplaceAll(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IVector ^>(info.This())) + { + return; + } + + VectorWrapper *wrapper = + VectorWrapper::Unwrap>(info.This()); + + if (info.Length() == 1 && + NodeRT::Utils::IsWinRtWrapperOf<::Platform::Array ^>(info[0])) + { + try + { + WrapperBase *itemsWrapper = + WrapperBase::Unwrap(info[0].As()); + ::Platform::Array ^ items = + (::Platform::Array ^) itemsWrapper->GetObjectInstance(); + wrapper->_instance->ReplaceAll(items); + return; + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"Bad arguments: no suitable overload found"))); + return; + } + } + + static void GetAt(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IVector ^>(info.This())) + { + return; + } + + VectorWrapper *wrapper = + VectorWrapper::Unwrap>(info.This()); + + if (info.Length() == 1 && info[0]->IsUint32()) + { + try + { + unsigned int index = info[0]->Uint32Value(Nan::GetCurrentContext()).FromMaybe(0); + + if (index >= wrapper->_instance->Size) + { + return; + } + T result; + result = wrapper->_instance->GetAt(index); + + if (wrapper->_getterFunc) + { + info.GetReturnValue().Set(wrapper->_getterFunc(result)); + } + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"Bad arguments: no suitable overload found"))); + return; + } + + return; + } + + static void SetAt(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IVector ^>(info.This())) + { + return; + } + + VectorWrapper *wrapper = + VectorWrapper::Unwrap>(info.This()); + + if (info.Length() == 2 && info[0]->IsUint32() && + wrapper->_checkTypeFunc(info[1])) + { + try + { + unsigned int index = info[0]->Uint32Value(Nan::GetCurrentContext()).FromMaybe(0); + + if (index >= wrapper->_instance->Size) + { + return; + } + + T item = wrapper->_convertToTypeFunc(info[1]); + + wrapper->_instance->SetAt(index, item); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"Bad arguments: no suitable overload found"))); + return; + } + + return; + } + + static void First(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IVector ^>(info.This())) + { + return; + } + + VectorWrapper *wrapper = + VectorWrapper::Unwrap>(info.This()); + + if (info.Length() == 0) + { + try + { + info.GetReturnValue().Set(IteratorWrapper::CreateIteratorWrapper( + wrapper->_instance->First(), wrapper->_getterFunc)); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"Bad arguments: no suitable overload found"))); + return; + } + + return; + } + + static void IndexOf(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IVector ^>(info.This())) + { + return; + } + + VectorWrapper *wrapper = + VectorWrapper::Unwrap>(info.This()); + + if (wrapper->_convertToTypeFunc == nullptr || + wrapper->_checkTypeFunc == nullptr) + { + Nan::ThrowError( + Nan::Error(NodeRT::Utils::NewString(L"Method isn't supported"))); + return; + } + + if (info.Length() == 1 && wrapper->_checkTypeFunc(info[0])) + { + try + { + T item = wrapper->_convertToTypeFunc(info[0]); + + unsigned int index; + bool result = wrapper->_instance->IndexOf(item, &index); + + Local resObj = Nan::New(); + Nan::Set(resObj, Nan::New("boolean").ToLocalChecked(), + Nan::New(result)); + Nan::Set(resObj, Nan::New("index").ToLocalChecked(), + Nan::New(index)); + info.GetReturnValue().Set(resObj); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"Bad arguments: no suitable overload found"))); + return; + } + + return; + } + + static void SizeGetter(Local property, + const Nan::PropertyCallbackInfo &info) + { + HandleScope scope; + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IVector ^>(info.This())) + { + return; + } + + VectorWrapper *wrapper = + VectorWrapper::Unwrap>(info.This()); + + try + { + info.GetReturnValue().Set(Nan::New(wrapper->_instance->Size)); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + + private: + ::Windows::Foundation::Collections::IVector ^ _instance; + std::function(T)> _getterFunc; + std::function)> _checkTypeFunc; + std::function)> _convertToTypeFunc; + static Persistent s_constructorTemplate; + }; + + template + Persistent VectorWrapper::s_constructorTemplate; + + template + class KeyValuePairWrapper : NodeRT::WrapperBase + { + public: + static void Init() + { + HandleScope scope; + + Local localRef = Nan::New(New); + s_constructorTemplate.Reset(localRef); + localRef->SetClassName( + Nan::New("Windows::Foundation::Collections:IKeyValuePair") + .ToLocalChecked()); + localRef->InstanceTemplate()->SetInternalFieldCount(1); + + Nan::SetAccessor(localRef->PrototypeTemplate(), + Nan::New("key").ToLocalChecked(), KeyGetter); + Nan::SetAccessor(localRef->PrototypeTemplate(), + Nan::New("value").ToLocalChecked(), ValueGetter); + + return; + } + + static Local CreateKeyValuePairWrapper( + ::Windows::Foundation::Collections::IKeyValuePair ^ winRtInstance, + const std::function(K)> &keyGetterFunc, + const std::function(V)> &valueGetterFunc) + { + EscapableHandleScope scope; + if (winRtInstance == nullptr) + { + return scope.Escape(Undefined()); + } + + if (s_constructorTemplate.IsEmpty()) + { + Init(); + } + + v8::Local args[] = {Undefined()}; + Local localRef = + Nan::New(s_constructorTemplate); + Local objectInstance = + Nan::NewInstance(Nan::GetFunction(localRef).ToLocalChecked(), 0, args) + .ToLocalChecked(); + if (objectInstance.IsEmpty()) + { + return scope.Escape(Undefined()); + } + + KeyValuePairWrapper *wrapperInstance = new KeyValuePairWrapper( + winRtInstance, keyGetterFunc, valueGetterFunc); + wrapperInstance->Wrap(objectInstance); + return scope.Escape(objectInstance); + } + + virtual ::Platform::Object ^ GetObjectInstance() const override + { + return _instance; + } + + private: + KeyValuePairWrapper(::Windows::Foundation::Collections::IKeyValuePair ^ + winRtInstance, + const std::function(K)> &keyGetterFunc, + const std::function(V)> &valueGetterFunc) + : _instance(winRtInstance), + _keyGetterFunc(keyGetterFunc), + _valueGetterFunc(valueGetterFunc) {} + + static void New(Nan::NAN_METHOD_ARGS_TYPE info) + { + NodeRT::Utils::SetHiddenValue( + info.This(), Nan::New("__winRtInstance__").ToLocalChecked(), + True()); + info.GetReturnValue().Set(info.This()); + } + + static void KeyGetter(Local property, + const Nan::PropertyCallbackInfo &info) + { + HandleScope scope; + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IKeyValuePair ^>( + info.This())) + { + return; + } + + KeyValuePairWrapper *wrapper = + KeyValuePairWrapper::Unwrap>( + info.This()); + + try + { + info.GetReturnValue().Set( + wrapper->_keyGetterFunc(wrapper->_instance->Key)); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + + static void ValueGetter(Local property, + const Nan::PropertyCallbackInfo &info) + { + HandleScope scope; + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IKeyValuePair ^>( + info.This())) + { + return; + } + + KeyValuePairWrapper *wrapper = + KeyValuePairWrapper::Unwrap>( + info.This()); + + try + { + info.GetReturnValue().Set( + wrapper->_valueGetterFunc(wrapper->_instance->Value)); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + + private: + ::Windows::Foundation::Collections::IKeyValuePair ^ _instance; + std::function(K)> _keyGetterFunc; + std::function(V)> _valueGetterFunc; + static Persistent s_constructorTemplate; + }; + + template + Persistent KeyValuePairWrapper::s_constructorTemplate; + + template + class MapViewWrapper : NodeRT::WrapperBase + { + public: + static void Init() + { + HandleScope scope; + + Local localRef = Nan::New(New); + s_constructorTemplate.Reset(localRef); + localRef->SetClassName( + Nan::New("Windows::Foundation::Collections:IMapView") + .ToLocalChecked()); + localRef->InstanceTemplate()->SetInternalFieldCount(1); + + Nan::SetPrototypeMethod(localRef, "hasKey", HasKey); + Nan::SetPrototypeMethod(localRef, "lookup", Lookup); + Nan::SetPrototypeMethod(localRef, "split", Split); + Nan::SetPrototypeMethod(localRef, "first", First); + + Nan::SetAccessor(localRef->PrototypeTemplate(), + Nan::New("size").ToLocalChecked(), SizeGetter); + Nan::SetAccessor(localRef->PrototypeTemplate(), + Nan::New("length").ToLocalChecked(), SizeGetter); + + return; + } + + static Local CreateMapViewWrapper( + ::Windows::Foundation::Collections::IMapView ^ winRtInstance, + const std::function(K)> &keyGetterFunc, + const std::function)> &checkKeyTypeFunc, + const std::function)> &convertToKeyTypeFunc, + const std::function(V)> &valueGetterFunc) + { + EscapableHandleScope scope; + if (winRtInstance == nullptr) + { + return scope.Escape(Undefined()); + } + + if (s_constructorTemplate.IsEmpty()) + { + Init(); + } + + v8::Local args[] = {Undefined()}; + Local localRef = + Nan::New(s_constructorTemplate); + Local objectInstance = + Nan::NewInstance(Nan::GetFunction(localRef).ToLocalChecked(), 0, args) + .ToLocalChecked(); + if (objectInstance.IsEmpty()) + { + return scope.Escape(Undefined()); + } + + MapViewWrapper *wrapperInstance = + new MapViewWrapper(winRtInstance, keyGetterFunc, checkKeyTypeFunc, + convertToKeyTypeFunc, valueGetterFunc); + wrapperInstance->Wrap(objectInstance); + return scope.Escape(objectInstance); + } + + virtual ::Platform::Object ^ GetObjectInstance() const override + { + return _instance; + } + + private: + MapViewWrapper(::Windows::Foundation::Collections::IMapView ^ + winRtInstance, + const std::function(K)> &keyGetterFunc, + const std::function)> &checkKeyTypeFunc, + const std::function)> &convertToKeyTypeFunc, + const std::function(V)> &valueGetterFunc) + : _instance(winRtInstance), + _keyGetterFunc(keyGetterFunc), + _checkKeyTypeFunc(checkKeyTypeFunc), + _convertToKeyTypeFunc(convertToKeyTypeFunc), + _valueGetterFunc(valueGetterFunc) {} + + static void New(Nan::NAN_METHOD_ARGS_TYPE info) + { + NodeRT::Utils::SetHiddenValue( + info.This(), Nan::New("__winRtInstance__").ToLocalChecked(), + True()); + + info.GetReturnValue().Set(info.This()); + } + + static void HasKey(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IMapView ^>( + info.This())) + { + return; + } + + MapViewWrapper *wrapper = + MapViewWrapper::Unwrap>(info.This()); + + if (info.Length() == 1 && wrapper->_checkKeyTypeFunc(info[0])) + { + try + { + K key = wrapper->_convertToKeyTypeFunc(info[0]); + + bool result = wrapper->_instance->HasKey(key); + + info.GetReturnValue().Set(Nan::New(result)); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"Bad arguments: no suitable overload found"))); + return; + } + + return; + } + + static void First(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IMapView ^>( + info.This())) + { + return; + } + + MapViewWrapper *wrapper = + MapViewWrapper::Unwrap>(info.This()); + + if (info.Length() == 0) + { + try + { + const std::function(K)> &keyGetter = + wrapper->_keyGetterFunc; + const std::function(V)> &valueGetter = + wrapper->_valueGetterFunc; + info.GetReturnValue().Set( + IteratorWrapper< + ::Windows::Foundation::Collections::IKeyValuePair ^>:: + CreateIteratorWrapper( + wrapper->_instance->First(), + [keyGetter, valueGetter]( + ::Windows::Foundation::Collections::IKeyValuePair ^ + value) + { + return KeyValuePairWrapper< + K, V>::CreateKeyValuePairWrapper(value, keyGetter, + valueGetter); + })); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"Bad arguments: no suitable overload found"))); + return; + } + + return; + } + + static void Lookup(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IMapView ^>( + info.This())) + { + return; + } + + MapViewWrapper *wrapper = + MapViewWrapper::Unwrap>(info.This()); + + if (info.Length() == 1 && wrapper->_checkKeyTypeFunc(info[0])) + { + try + { + K key = wrapper->_convertToKeyTypeFunc(info[0]); + + V result = wrapper->_instance->Lookup(key); + + info.GetReturnValue().Set(wrapper->_valueGetterFunc(result)); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"Bad arguments: no suitable overload found"))); + return; + } + + return; + } + + static void Split(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IMapView ^>( + info.This())) + { + return; + } + + MapViewWrapper *wrapper = + MapViewWrapper::Unwrap>(info.This()); + + if (info.Length() == 0) + { + try + { + ::Windows::Foundation::Collections::IMapView ^ first; + ::Windows::Foundation::Collections::IMapView ^ second; + + wrapper->_instance->Split(&first, &second); + + Local resObj = Nan::New(); + Nan::Set( + resObj, Nan::New("first").ToLocalChecked(), + MapViewWrapper::CreateMapViewWrapper( + first, wrapper->_keyGetterFunc, wrapper->_checkTypeFunc, + wrapper->_convertToKeyTypeFunc, wrapper->_valueGetterFunc)); + Nan::Set( + resObj, Nan::New("second").ToLocalChecked(), + MapViewWrapper::CreateMapViewWrapper( + second, wrapper->_keyGetterFunc, wrapper->_checkTypeFunc, + wrapper->_convertToKeyTypeFunc, wrapper->_valueGetterFunc)); + info.GetReturnValue().Set(resObj); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"Bad arguments: no suitable overload found"))); + return; + } + + return; + } + + static void SizeGetter(Local property, + const Nan::PropertyCallbackInfo &info) + { + HandleScope scope; + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IMapView ^>( + info.This())) + { + return; + } + + MapViewWrapper *wrapper = + MapViewWrapper::Unwrap>(info.This()); + + try + { + info.GetReturnValue().Set(Nan::New(wrapper->_instance->Size)); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + + private: + ::Windows::Foundation::Collections::IMapView ^ _instance; + std::function)> _checkTypeFunc; + std::function(K)> _keyGetterFunc; + std::function)> _convertToKeyTypeFunc; + std::function(V)> _valueGetterFunc; + std::function)> _checkKeyTypeFunc; + static Persistent s_constructorTemplate; + }; + + template + Persistent MapViewWrapper::s_constructorTemplate; + + template + class MapWrapper : NodeRT::WrapperBase + { + public: + static void Init() + { + HandleScope scope; + + Local localRef = Nan::New(New); + s_constructorTemplate.Reset(localRef); + localRef->SetClassName( + Nan::New("Windows::Foundation::Collections:IMap") + .ToLocalChecked()); + localRef->InstanceTemplate()->SetInternalFieldCount(1); + + Nan::SetPrototypeMethod(localRef, "hasKey", HasKey); + Nan::SetPrototypeMethod(localRef, "lookup", Lookup); + Nan::SetPrototypeMethod(localRef, "getView", GetView); + Nan::SetPrototypeMethod(localRef, "clear", Clear); + Nan::SetPrototypeMethod(localRef, "insert", Insert); + Nan::SetPrototypeMethod(localRef, "remove", Remove); + Nan::SetPrototypeMethod(localRef, "first", First); + + Nan::SetAccessor(localRef->PrototypeTemplate(), + Nan::New("size").ToLocalChecked(), SizeGetter); + Nan::SetAccessor(localRef->PrototypeTemplate(), + Nan::New("length").ToLocalChecked(), SizeGetter); + + return; + } + + static Local CreateMapWrapper( + ::Windows::Foundation::Collections::IMap ^ winRtInstance, + const std::function(K)> &keyGetterFunc, + const std::function)> &checkKeyTypeFunc, + const std::function)> &convertToKeyTypeFunc, + const std::function(V)> &valueGetterFunc, + const std::function)> &checkValueTypeFunc, + const std::function)> &convertToValueTypeFunc) + { + EscapableHandleScope scope; + if (winRtInstance == nullptr) + { + return scope.Escape(Undefined()); + } + + if (s_constructorTemplate.IsEmpty()) + { + Init(); + } + + v8::Local args[] = {Undefined()}; + Local localRef = + Nan::New(s_constructorTemplate); + Local objectInstance = + Nan::NewInstance(Nan::GetFunction(localRef).ToLocalChecked(), 0, args) + .ToLocalChecked(); + if (objectInstance.IsEmpty()) + { + return scope.Escape(Undefined()); + } + + MapWrapper *wrapperInstance = new MapWrapper( + winRtInstance, keyGetterFunc, checkKeyTypeFunc, convertToKeyTypeFunc, + valueGetterFunc, checkValueTypeFunc, convertToValueTypeFunc); + wrapperInstance->Wrap(objectInstance); + return scope.Escape(objectInstance); + } + + virtual ::Platform::Object ^ GetObjectInstance() const override + { + return _instance; + } + + private: + MapWrapper(::Windows::Foundation::Collections::IMap ^ winRtInstance, + const std::function(K)> &keyGetterFunc, + const std::function)> &checkKeyTypeFunc, + const std::function)> &convertToKeyTypeFunc, + const std::function(V)> &valueGetterFunc, + const std::function)> &checkValueTypeFunc, + const std::function)> &convertToValueTypeFunc) + : _instance(winRtInstance), + _keyGetterFunc(keyGetterFunc), + _checkKeyTypeFunc(checkKeyTypeFunc), + _convertToKeyTypeFunc(convertToKeyTypeFunc), + _valueGetterFunc(valueGetterFunc), + _checkValueTypeFunc(checkValueTypeFunc), + _convertToValueTypeFunc(convertToValueTypeFunc) {} + + static void New(Nan::NAN_METHOD_ARGS_TYPE info) + { + NodeRT::Utils::SetHiddenValue( + info.This(), Nan::New("__winRtInstance__").ToLocalChecked(), + True()); + + info.GetReturnValue().Set(info.This()); + } + + static void HasKey(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IMap ^>(info.This())) + { + return; + } + + MapWrapper *wrapper = + MapWrapper::Unwrap>(info.This()); + + if (info.Length() == 1 && wrapper->_checkKeyTypeFunc(info[0])) + { + try + { + K key = wrapper->_convertToKeyTypeFunc(info[0]); + + bool result = wrapper->_instance->HasKey(key); + + info.GetReturnValue().Set(Nan::New(result)); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"Bad arguments: no suitable overload found"))); + return; + } + + return; + } + + static void Remove(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IMap ^>(info.This())) + { + return; + } + + MapWrapper *wrapper = + MapWrapper::Unwrap>(info.This()); + + if (info.Length() == 1 && wrapper->_checkKeyTypeFunc(info[0])) + { + try + { + K key = wrapper->_convertToKeyTypeFunc(info[0]); + + wrapper->_instance->Remove(key); + + return; + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"Bad arguments: no suitable overload found"))); + return; + } + } + + static void Insert(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IMap ^>(info.This())) + { + return; + } + + MapWrapper *wrapper = + MapWrapper::Unwrap>(info.This()); + + if (info.Length() == 2 && wrapper->_checkKeyTypeFunc(info[0]) && + wrapper->_checkValueTypeFunc(info[1])) + { + try + { + K key = wrapper->_convertToKeyTypeFunc(info[0]); + V value = wrapper->_convertToValueTypeFunc(info[1]); + + bool result = wrapper->_instance->Insert(key, value); + + info.GetReturnValue().Set(Nan::New(result)); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"Bad arguments: no suitable overload found"))); + return; + } + } + + static void First(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IMap ^>(info.This())) + { + return; + } + + MapWrapper *wrapper = + MapWrapper::Unwrap>(info.This()); + + if (info.Length() == 0) + { + try + { + const std::function(K)> &keyGetter = + wrapper->_keyGetterFunc; + const std::function(V)> &valueGetter = + wrapper->_valueGetterFunc; + info.GetReturnValue().Set( + IteratorWrapper< + ::Windows::Foundation::Collections::IKeyValuePair ^>:: + CreateIteratorWrapper( + wrapper->_instance->First(), + [keyGetter, valueGetter]( + ::Windows::Foundation::Collections::IKeyValuePair ^ + value) + { + return KeyValuePairWrapper< + K, V>::CreateKeyValuePairWrapper(value, keyGetter, + valueGetter); + })); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"Bad arguments: no suitable overload found"))); + return; + } + + return; + } + + static void Lookup(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IMap ^>(info.This())) + { + return; + } + + MapWrapper *wrapper = + MapWrapper::Unwrap>(info.This()); + + if (info.Length() == 1 && wrapper->_checkKeyTypeFunc(info[0])) + { + try + { + K key = wrapper->_convertToKeyTypeFunc(info[0]); + + V result = wrapper->_instance->Lookup(key); + + info.GetReturnValue().Set(wrapper->_valueGetterFunc(result)); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"Bad arguments: no suitable overload found"))); + return; + } + + return; + } + + static void GetView(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IMap ^>(info.This())) + { + return; + } + + MapWrapper *wrapper = + MapWrapper::Unwrap>(info.This()); + + if (info.Length() == 0) + { + try + { + ::Windows::Foundation::Collections::IMapView ^ result = + wrapper->_instance->GetView(); + + info.GetReturnValue().Set(MapViewWrapper::CreateMapViewWrapper( + result, wrapper->_keyGetterFunc, wrapper->_checkKeyTypeFunc, + wrapper->_convertToKeyTypeFunc, wrapper->_valueGetterFunc)); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"Bad arguments: no suitable overload found"))); + return; + } + } + + static void Clear(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IMap ^>(info.This())) + { + return; + } + + MapWrapper *wrapper = + MapWrapper::Unwrap>(info.This()); + + if (info.Length() == 0) + { + try + { + wrapper->_instance->Clear(); + return; + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"Bad arguments: no suitable overload found"))); + return; + } + } + + static void SizeGetter(Local property, + const Nan::PropertyCallbackInfo &info) + { + HandleScope scope; + if (!NodeRT::Utils::IsWinRtWrapperOf< + ::Windows::Foundation::Collections::IMap ^>(info.This())) + { + return; + } + + MapWrapper *wrapper = + MapWrapper::Unwrap>(info.This()); + + try + { + info.GetReturnValue().Set(Nan::New(wrapper->_instance->Size)); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + + private: + ::Windows::Foundation::Collections::IMap ^ _instance; + + std::function(K)> _keyGetterFunc; + std::function)> _convertToKeyTypeFunc; + std::function)> _checkKeyTypeFunc; + + std::function(V)> _valueGetterFunc; + std::function)> _convertToValueTypeFunc; + std::function)> _checkValueTypeFunc; + + static Persistent s_constructorTemplate; + }; + + template + Persistent MapWrapper::s_constructorTemplate; + + } // namespace Collections +}; // namespace NodeRT diff --git a/desktop/addons/windows-pushnotifications/LICENSE b/desktop/addons/windows-pushnotifications/LICENSE new file mode 100644 --- /dev/null +++ b/desktop/addons/windows-pushnotifications/LICENSE @@ -0,0 +1,194 @@ +Copyright 2019, The NodeRT Contributors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +``` +------------------------------------------------------------------------- + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS +``` diff --git a/desktop/addons/windows-pushnotifications/NodeRtUtils.h b/desktop/addons/windows-pushnotifications/NodeRtUtils.h new file mode 100644 --- /dev/null +++ b/desktop/addons/windows-pushnotifications/NodeRtUtils.h @@ -0,0 +1,148 @@ +// Copyright (c) The NodeRT Contributors +// All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the ""License""); you may +// not use this file except in compliance with the License. You may obtain a +// copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS +// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY +// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +// MERCHANTABLITY OR NON-INFRINGEMENT. +// +// See the Apache Version 2.0 License for specific language governing +// permissions and limitations under the License. + +#pragma once + +#include +#include "nan.h" + +#define WCHART_NOT_BUILTIN_IN_NODE 1 + +namespace NodeRT +{ + namespace Utils + { + + v8::Local WinRtExceptionToJsError(Platform::Exception ^ exception); + + void ThrowWinRtExceptionInJs(Platform::Exception ^ exception); + + // creates an object with the following structure: + // { + // "callback" : [callback function] + // "domain" : [the domain in which the async function/event was + // called/registered] (this is optional) + // } + v8::Local CreateCallbackObjectInDomain( + v8::Local callback); + + // Calls the callback in the appropriate domwin, expects an object in the + // following format: + // { + // "callback" : [callback fuction] + // "domain" : [the domain in which the async function/event was + // called/registered] (this is optional) + // } + v8::Local CallCallbackInDomain(v8::Local callbackObject, + int argc, + v8::Local argv[]); + + v8::Local NewString(const wchar_t *str); + + const wchar_t *StringToWchar(v8::String::Value &str); + + ::Platform::String ^ V8StringToPlatformString(v8::Local value); + +#ifdef WCHART_NOT_BUILTIN_IN_NODE + // compares 2 strings using a case insensitive comparison + bool CaseInsenstiveEquals(const wchar_t *str1, const uint16_t *str2); +#endif + + // compares 2 strings using a case insensitive comparison + bool CaseInsenstiveEquals(const wchar_t *str1, const wchar_t *str2); + + // registers the namespace & required object on the global object + void RegisterNameSpace(const char *ns, v8::Local nsExports); + + v8::Local CreateExternalWinRTObject(const char *ns, + const char *objectName, + ::Platform::Object ^ instance); + + bool IsWinRtWrapper(v8::Local value); + + template + bool IsWinRtWrapperOf(v8::Local value) + { + if (!IsWinRtWrapper(value)) + { + return false; + } + + if (value->IsNull()) + { + return true; + } + + WrapperBase *wrapper = + Nan::ObjectWrap::Unwrap(value.As()); + + if (wrapper->GetObjectInstance() == nullptr) + { + return false; + } + + try + { + T instance = dynamic_cast(wrapper->GetObjectInstance()); + return (instance != nullptr); + } + catch (...) + { + return false; + } + } + + ::Platform::Object ^ GetObjectInstance(v8::Local value); + + void SetHiddenValue(v8::Local obj, + v8::Local symbol, + v8::Local data); + void SetHiddenValueWithObject(v8::Local obj, + v8::Local symbol, + v8::Local data); + v8::Local GetHiddenValue(v8::Local obj, + v8::Local symbol); + + v8::Local DateTimeToJS(::Windows::Foundation::DateTime value); + ::Windows::Foundation::TimeSpan TimeSpanFromMilli(int64_t millis); + ::Windows::Foundation::DateTime DateTimeFromJSDate(v8::Local value); + + bool IsGuid(v8::Local value); + ::Platform::Guid GuidFromJs(v8::Local value); + v8::Local GuidToJs(::Platform::Guid guid); + + v8::Local ColorToJs(::Windows::UI::Color color); + ::Windows::UI::Color ColorFromJs(v8::Local value); + bool IsColor(v8::Local value); + + v8::Local RectToJs(::Windows::Foundation::Rect rect); + ::Windows::Foundation::Rect RectFromJs(v8::Local value); + bool IsRect(v8::Local value); + + v8::Local PointToJs(::Windows::Foundation::Point point); + ::Windows::Foundation::Point PointFromJs(v8::Local value); + bool IsPoint(v8::Local value); + + v8::Local SizeToJs(::Windows::Foundation::Size size); + ::Windows::Foundation::Size SizeFromJs(v8::Local value); + bool IsSize(v8::Local value); + + wchar_t GetFirstChar(v8::Local value); + v8::Local JsStringFromChar(wchar_t value); + + ::Windows::Foundation::HResult HResultFromJsInt32(int32_t value); + + } // namespace Utils +} // namespace NodeRT \ No newline at end of file diff --git a/desktop/addons/windows-pushnotifications/NodeRtUtils.cpp b/desktop/addons/windows-pushnotifications/NodeRtUtils.cpp new file mode 100644 --- /dev/null +++ b/desktop/addons/windows-pushnotifications/NodeRtUtils.cpp @@ -0,0 +1,809 @@ +// Copyright (c) The NodeRT Contributors +// All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the ""License""); you may +// not use this file except in compliance with the License. You may obtain a +// copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS +// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY +// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +// MERCHANTABLITY OR NON-INFRINGEMENT. +// +// See the Apache Version 2.0 License for specific language governing +// permissions and limitations under the License. + +#include "NodeRtUtils.h" +#include +#include +#include "OpaqueWrapper.h" +#include "nan.h" + +#define WCHART_NOT_BUILTIN_IN_NODE 1 + +namespace NodeRT +{ + namespace Utils + { + + using Nan::EscapableHandleScope; + using Nan::False; + using Nan::HandleScope; + using Nan::MaybeLocal; + using Nan::Null; + using Nan::Persistent; + using Nan::True; + using Nan::Undefined; + using v8::Boolean; + using v8::Date; + using v8::Function; + using v8::FunctionTemplate; + using v8::Integer; + using v8::Local; + using v8::Number; + using v8::Object; + using v8::Primitive; + using v8::PropertyAttribute; + using v8::String; + using v8::Value; + + v8::Local WinRtExceptionToJsError(Platform::Exception ^ exception) + { + EscapableHandleScope scope; + + if (exception == nullptr) + { + return scope.Escape(Undefined()); + } + + // we use casting here in case that wchar_t is not a built-in type + const wchar_t *errorMessage = exception->Message->Data(); + unsigned int length = exception->Message->Length(); + + Local error = Nan::Error( + Nan::New(reinterpret_cast(errorMessage)) + .ToLocalChecked()); + Nan::Set(Nan::To(error).ToLocalChecked(), + Nan::New("HRESULT").ToLocalChecked(), + Nan::New(exception->HResult)); + + return scope.Escape(error); + } + + void ThrowWinRtExceptionInJs(Platform::Exception ^ exception) + { + if (exception == nullptr) + { + return; + } + + Nan::ThrowError(WinRtExceptionToJsError(exception)); + } + + // creates an object with the following structure: + // { + // "callback" : [callback fuction] + // "domain" : [the domain in which the async function/event was + // called/registered] (this is optional) + // } + Local CreateCallbackObjectInDomain(Local callback) + { + EscapableHandleScope scope; + + // get the current domain: + MaybeLocal callbackObject = Nan::New(); + + Nan::Set(callbackObject.ToLocalChecked(), + Nan::New("callback").ToLocalChecked(), callback); + + MaybeLocal processVal = + Nan::Get(Nan::GetCurrentContext()->Global(), + Nan::New("process").ToLocalChecked()); + v8::Local process = + Nan::To(processVal.ToLocalChecked()).ToLocalChecked(); + if (process.IsEmpty() || Nan::Equals(process, Undefined()).FromMaybe(true)) + { + return scope.Escape(callbackObject.ToLocalChecked()); + } + + MaybeLocal currentDomain = + Nan::Get(process, Nan::New("domain").ToLocalChecked()); + + if (!currentDomain.IsEmpty() && + !Nan::Equals(currentDomain.ToLocalChecked(), Undefined()) + .FromMaybe(true)) + { + Nan::Set(callbackObject.ToLocalChecked(), + Nan::New("domain").ToLocalChecked(), + currentDomain.ToLocalChecked()); + } + + return scope.Escape(callbackObject.ToLocalChecked()); + } + + // Calls the callback in the appropriate domwin, expects an object in the + // following format: + // { + // "callback" : [callback function] + // "domain" : [the domain in which the async function/event was + // called/registered] (this is optional) + // } + Local CallCallbackInDomain(Local callbackObject, + int argc, + Local argv[]) + { + Nan::AsyncResource asyncResource(Nan::New("CallCallbackInDomain").ToLocalChecked()); + return asyncResource.runInAsyncScope( + callbackObject, + Nan::New("callback").ToLocalChecked(), argc, + argv) + .FromMaybe(v8::Local()); + } + + ::Platform::Object ^ + GetObjectInstance(Local value) { + // nulls are allowed when a WinRT wrapped object is expected + if (value->IsNull()) + { + return nullptr; + } + + WrapperBase *wrapper = Nan::ObjectWrap::Unwrap( + Nan::To(value).ToLocalChecked()); + return wrapper->GetObjectInstance(); + } + + Local NewString(const wchar_t *str) + { +#ifdef WCHART_NOT_BUILTIN_IN_NODE + return Nan::New(reinterpret_cast(str)) + .ToLocalChecked(); +#else + return Nan::New(str).ToLocalChecked(); +#endif + } + + const wchar_t *StringToWchar(v8::String::Value &str) + { +#ifdef WCHART_NOT_BUILTIN_IN_NODE + return reinterpret_cast(*str); +#else + return *str; +#endif + } + + // Note: current implementation converts any JS value that has a toString method + // to a ::Platform::String^ Changes to this code might break the Collection + // Convertor logic + ::Platform::String ^ + V8StringToPlatformString(Local value) { + v8::String::Value stringVal(v8::Isolate::GetCurrent(), value); +#ifdef WCHART_NOT_BUILTIN_IN_NODE + return ref new Platform::String( + reinterpret_cast(*stringVal)); +#else + return ref new Platform::String(*stringVal); +#endif + } + +#ifndef min + size_t min(size_t one, size_t two) + { + if (one < two) + { + return one; + } + + return two; + } +#endif + +#ifdef WCHART_NOT_BUILTIN_IN_NODE + // compares 2 strings using a case insensitive comparison + bool CaseInsenstiveEquals(const wchar_t *str1, const uint16_t *str2) + { + int maxCount = static_cast( + min(wcslen(str1), wcslen(reinterpret_cast(str2)))); + return (_wcsnicmp(str1, reinterpret_cast(str2), maxCount) == + 0); + } +#endif + + // compares 2 strings using a case insensitive comparison + bool CaseInsenstiveEquals(const wchar_t *str1, const wchar_t *str2) + { + int maxCount = static_cast(min(wcslen(str1), wcslen(str2))); + return (_wcsnicmp(str1, str2, maxCount) == 0); + } + + void RegisterNameSpace(const char *ns, Local nsExports) + { + HandleScope scope; + Local global = Nan::GetCurrentContext()->Global(); + + if (!Nan::Has(global, + Nan::New("__winRtNamespaces__").ToLocalChecked()) + .FromMaybe(false)) + { + Nan::ForceSet(global, + Nan::New("__winRtNamespaces__").ToLocalChecked(), + Nan::New(), + (v8::PropertyAttribute)(v8::PropertyAttribute::DontEnum & + v8::PropertyAttribute::DontDelete)); + } + + MaybeLocal nsObject = Nan::Get( + global, Nan::New("__winRtNamespaces__").ToLocalChecked()); + Nan::Set(Nan::To(nsObject.ToLocalChecked()).ToLocalChecked(), + Nan::New(ns).ToLocalChecked(), nsExports); + } + + Local CreateExternalWinRTObject(const char *ns, + const char *objectName, + ::Platform::Object ^ instance) + { + EscapableHandleScope scope; + Local opaqueWrapper = CreateOpaqueWrapper(instance); + + Local global = Nan::GetCurrentContext()->Global(); + if (!Nan::Has(global, + Nan::New("__winRtNamespaces__").ToLocalChecked()) + .FromMaybe(false)) + { + return scope.Escape(opaqueWrapper); + } + + Local winRtObj = + Nan::To( + Nan::Get(global, + Nan::New("__winRtNamespaces__").ToLocalChecked()) + .ToLocalChecked()) + .ToLocalChecked(); + + Local nsSymbol = Nan::New(ns).ToLocalChecked(); + if (!Nan::Has(winRtObj, nsSymbol).FromMaybe(false)) + { + return scope.Escape(opaqueWrapper); + } + + v8::MaybeLocal maybeLocalRef = Nan::Get(winRtObj, nsSymbol); + + if (maybeLocalRef.IsEmpty()) + { + return scope.Escape(opaqueWrapper); + } + + Local nsObjectValue = maybeLocalRef.ToLocalChecked(); + + if (Nan::Equals(nsObjectValue, Undefined()).FromMaybe(false)) + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString( + L"Failed to obtain external namespace object"))); + return Undefined(); + } + + Local nsObject = Nan::To(nsObjectValue).ToLocalChecked(); + + Local objectNameSymbol = + Nan::New(objectName).ToLocalChecked(); + if (!Nan::Has(nsObject, objectNameSymbol).FromMaybe(false)) + { + return scope.Escape(opaqueWrapper); + } + + Local objectFunc = + Nan::Get(nsObject, objectNameSymbol).ToLocalChecked().As(); + Local args[] = {opaqueWrapper}; + return scope.Escape( + Nan::NewInstance(objectFunc, _countof(args), args).ToLocalChecked()); + } + + bool IsWinRtWrapper(Local value) + { + if (value.IsEmpty() || (!value->IsObject() && !value->IsNull())) + { + return false; + } + + // allow passing nulls when a WinRT wrapped object is expected + if (value->IsNull()) + { + return true; + } + + if (NodeRT::OpaqueWrapper::IsOpaqueWrapper(value)) + { + return true; + } + + Local hiddenVal = + GetHiddenValue(Nan::To(value).ToLocalChecked(), + Nan::New("__winRtInstance__").ToLocalChecked()); + + return (!hiddenVal.IsEmpty() && hiddenVal->IsTrue()); + } + + void SetHiddenValue(Local obj, + Local symbol, + Local data) + { + Nan::ForceSet(obj, symbol, data, + static_cast(v8::ReadOnly & v8::DontEnum)); + } + + void SetHiddenValueWithObject(Local obj, + Local symbol, + Local data) + { + Nan::ForceSet(obj, symbol, data, + static_cast(v8::ReadOnly & v8::DontEnum)); + } + + Local GetHiddenValue(Local obj, Local symbol) + { + return Nan::Get(obj, symbol).ToLocalChecked(); + } + + ::Windows::Foundation::TimeSpan TimeSpanFromMilli(int64_t millis) + { + ::Windows::Foundation::TimeSpan timeSpan; + timeSpan.Duration = millis * 10000; + + return timeSpan; + } + + ::Windows::Foundation::DateTime DateTimeFromJSDate(Local value) + { + ::Windows::Foundation::DateTime time; + time.UniversalTime = 0; + if (value->IsDate()) + { + // 116444736000000000 = The time in 100 nanoseconds between 1/1/1970(UTC) to + // 1/1/1601(UTC) ux_time = (Current time since 1601 in 100 nano sec + // units)/10000 - 116444736000000000; + time.UniversalTime = value->IntegerValue(Nan::GetCurrentContext()).FromMaybe(0) * 10000 + 116444736000000000; + } + + return time; + } + + Local DateTimeToJS(::Windows::Foundation::DateTime value) + { + // 116444736000000000 = The time 100 nanoseconds between 1/1/1970(UTC) to + // 1/1/1601(UTC) ux_time = (Current time since 1601 in 100 nano sec + // units)/10000 - 11644473600000; + return Nan::New(value.UniversalTime / 10000.0 - 11644473600000) + .ToLocalChecked(); + } + + bool StrToGuid(Local value, LPCLSID guid) + { + if (value.IsEmpty() || !value->IsString()) + { + return false; + } + + v8::String::Value stringVal(v8::Isolate::GetCurrent(), value); + std::wstring guidStr(L"{"); + guidStr += StringToWchar(stringVal); + guidStr += L"}"; + + HRESULT hr = CLSIDFromString(guidStr.c_str(), guid); + if (FAILED(hr)) + { + return false; + } + + return true; + } + + bool IsGuid(Local value) + { + GUID guid; + return StrToGuid(value, &guid); + } + + ::Platform::Guid GuidFromJs(Local value) + { + GUID guid; + if (!StrToGuid(value, &guid)) + { + return ::Platform::Guid(); + } + + return ::Platform::Guid(guid); + } + + Local GuidToJs(::Platform::Guid guid) + { + OLECHAR *bstrGuid; + StringFromCLSID(guid, &bstrGuid); + + Local strVal = NewString(bstrGuid); + CoTaskMemFree(bstrGuid); + return strVal; + } + + Local ColorToJs(::Windows::UI::Color color) + { + EscapableHandleScope scope; + Local obj = Nan::New(); + + Nan::Set(obj, Nan::New("G").ToLocalChecked(), + Nan::New(color.G)); + Nan::Set(obj, Nan::New("B").ToLocalChecked(), + Nan::New(color.B)); + Nan::Set(obj, Nan::New("A").ToLocalChecked(), + Nan::New(color.A)); + Nan::Set(obj, Nan::New("R").ToLocalChecked(), + Nan::New(color.R)); + + return scope.Escape(obj); + } + + ::Windows::UI::Color ColorFromJs(Local value) + { + ::Windows::UI::Color retVal = ::Windows::UI::Colors::Black; + if (!value->IsObject()) + { + Nan::ThrowError(Nan::Error( + NodeRT::Utils::NewString(L"Value to set is of unexpected type"))); + return retVal; + } + + Local obj = Nan::To(value).ToLocalChecked(); + if (!Nan::Has(obj, Nan::New("G").ToLocalChecked()).FromMaybe(false)) + { + retVal.G = static_cast( + Nan::To(Nan::Get(obj, Nan::New("G").ToLocalChecked()) + .ToLocalChecked()) + .FromMaybe(0)); + } + + if (!Nan::Has(obj, Nan::New("A").ToLocalChecked()).FromMaybe(false)) + { + retVal.G = static_cast( + Nan::To(Nan::Get(obj, Nan::New("A").ToLocalChecked()) + .ToLocalChecked()) + .FromMaybe(0)); + } + + if (!Nan::Has(obj, Nan::New("B").ToLocalChecked()).FromMaybe(false)) + { + retVal.G = static_cast( + Nan::To(Nan::Get(obj, Nan::New("B").ToLocalChecked()) + .ToLocalChecked()) + .FromMaybe(0)); + } + + if (!Nan::Has(obj, Nan::New("R").ToLocalChecked()).FromMaybe(false)) + { + retVal.G = static_cast( + Nan::To(Nan::Get(obj, Nan::New("R").ToLocalChecked()) + .ToLocalChecked()) + .FromMaybe(0)); + } + + return retVal; + } + + bool IsColor(Local value) + { + if (!value->IsObject()) + { + return false; + } + + Local obj = Nan::To(value).ToLocalChecked(); + if (!Nan::Has(obj, Nan::New("G").ToLocalChecked()).FromMaybe(false)) + { + return false; + } + + if (!Nan::Has(obj, Nan::New("A").ToLocalChecked()).FromMaybe(false)) + { + return false; + } + + if (!Nan::Has(obj, Nan::New("B").ToLocalChecked()).FromMaybe(false)) + { + return false; + } + + if (!Nan::Has(obj, Nan::New("R").ToLocalChecked()).FromMaybe(false)) + { + return false; + } + + return true; + } + + Local RectToJs(::Windows::Foundation::Rect rect) + { + EscapableHandleScope scope; + Local obj = Nan::New(); + + Nan::Set(obj, Nan::New("bottom").ToLocalChecked(), + Nan::New(rect.Bottom)); + Nan::Set(obj, Nan::New("height").ToLocalChecked(), + Nan::New(rect.Height)); + Nan::Set(obj, Nan::New("left").ToLocalChecked(), + Nan::New(rect.Left)); + Nan::Set(obj, Nan::New("right").ToLocalChecked(), + Nan::New(rect.Right)); + Nan::Set(obj, Nan::New("top").ToLocalChecked(), + Nan::New(rect.Top)); + Nan::Set(obj, Nan::New("width").ToLocalChecked(), + Nan::New(rect.Width)); + Nan::Set(obj, Nan::New("x").ToLocalChecked(), + Nan::New(rect.X)); + Nan::Set(obj, Nan::New("y").ToLocalChecked(), + Nan::New(rect.Y)); + + return scope.Escape(obj); + } + + ::Windows::Foundation::Rect RectFromJs(Local value) + { + ::Windows::Foundation::Rect rect = ::Windows::Foundation::Rect::Empty; + + if (!value->IsObject()) + { + Nan::ThrowError(Nan::Error( + NodeRT::Utils::NewString(L"Value to set is of unexpected type"))); + return rect; + } + + Local obj = Nan::To(value).ToLocalChecked(); + + if (Nan::Has(obj, Nan::New("x").ToLocalChecked()).FromMaybe(false)) + { + rect.X = static_cast( + Nan::To(Nan::Get(obj, Nan::New("x").ToLocalChecked()) + .ToLocalChecked()) + .FromMaybe(0.0)); + } + + if (Nan::Has(obj, Nan::New("y").ToLocalChecked()).FromMaybe(false)) + { + rect.Y = static_cast( + Nan::To(Nan::Get(obj, Nan::New("y").ToLocalChecked()) + .ToLocalChecked()) + .FromMaybe(0.0)); + } + + if (Nan::Has(obj, Nan::New("height").ToLocalChecked()) + .FromMaybe(false)) + { + rect.Height = static_cast( + Nan::To( + Nan::Get(obj, Nan::New("height").ToLocalChecked()) + .ToLocalChecked()) + .FromMaybe(0.0)); + } + + if (Nan::Has(obj, Nan::New("width").ToLocalChecked()) + .FromMaybe(false)) + { + rect.Width = static_cast( + Nan::To( + Nan::Get(obj, Nan::New("width").ToLocalChecked()) + .ToLocalChecked()) + .FromMaybe(0.0)); + } + + return rect; + } + + bool IsRect(Local value) + { + if (!value->IsObject()) + { + return false; + } + + Local obj = Nan::To(value).ToLocalChecked(); + + if (!Nan::Has(obj, Nan::New("x").ToLocalChecked()).FromMaybe(false)) + { + return false; + } + + if (!Nan::Has(obj, Nan::New("y").ToLocalChecked()).FromMaybe(false)) + { + return false; + } + + if (!Nan::Has(obj, Nan::New("height").ToLocalChecked()) + .FromMaybe(false)) + { + return false; + } + + if (!Nan::Has(obj, Nan::New("width").ToLocalChecked()) + .FromMaybe(false)) + { + return false; + } + + return true; + } + + Local PointToJs(::Windows::Foundation::Point point) + { + EscapableHandleScope scope; + Local obj = Nan::New(); + + Nan::Set(obj, Nan::New("x").ToLocalChecked(), + Nan::New(point.X)); + Nan::Set(obj, Nan::New("y").ToLocalChecked(), + Nan::New(point.Y)); + + return scope.Escape(obj); + } + + ::Windows::Foundation::Point PointFromJs(Local value) + { + ::Windows::Foundation::Point point(0, 0); + + if (!value->IsObject()) + { + Nan::ThrowError(Nan::Error( + NodeRT::Utils::NewString(L"Value to set is of unexpected type"))); + return point; + } + + Local obj = Nan::To(value).ToLocalChecked(); + + if (Nan::Has(obj, Nan::New("x").ToLocalChecked()).FromMaybe(false)) + { + point.X = static_cast( + Nan::To(Nan::Get(obj, Nan::New("x").ToLocalChecked()) + .ToLocalChecked()) + .FromMaybe(0.0)); + } + + if (Nan::Has(obj, Nan::New("y").ToLocalChecked()).FromMaybe(false)) + { + point.Y = static_cast( + Nan::To(Nan::Get(obj, Nan::New("y").ToLocalChecked()) + .ToLocalChecked()) + .FromMaybe(0.0)); + } + + return point; + } + + bool IsPoint(Local value) + { + if (!value->IsObject()) + { + return false; + } + + Local obj = Nan::To(value).ToLocalChecked(); + + if (!Nan::Has(obj, Nan::New("x").ToLocalChecked()).FromMaybe(false)) + { + return false; + } + + if (!Nan::Has(obj, Nan::New("y").ToLocalChecked()).FromMaybe(false)) + { + return false; + } + + return true; + } + + Local SizeToJs(::Windows::Foundation::Size size) + { + EscapableHandleScope scope; + Local obj = Nan::New(); + + Nan::Set(obj, Nan::New("height").ToLocalChecked(), + Nan::New(size.Height)); + Nan::Set(obj, Nan::New("width").ToLocalChecked(), + Nan::New(size.Width)); + + return scope.Escape(obj); + } + + ::Windows::Foundation::Size SizeFromJs(Local value) + { + ::Windows::Foundation::Size size(0, 0); + + if (!value->IsObject()) + { + Nan::ThrowError(Nan::Error( + NodeRT::Utils::NewString(L"Value to set is of unexpected type"))); + return size; + } + + Local obj = Nan::To(value).ToLocalChecked(); + + if (Nan::Has(obj, Nan::New("height").ToLocalChecked()) + .FromMaybe(false)) + { + size.Height = static_cast( + Nan::To( + Nan::Get(obj, Nan::New("height").ToLocalChecked()) + .ToLocalChecked()) + .FromMaybe(0.0)); + } + + if (Nan::Has(obj, Nan::New("width").ToLocalChecked()) + .FromMaybe(false)) + { + size.Width = static_cast( + Nan::To( + Nan::Get(obj, Nan::New("width").ToLocalChecked()) + .ToLocalChecked()) + .FromMaybe(0.0)); + } + + return size; + } + + bool IsSize(Local value) + { + if (!value->IsObject()) + { + return false; + } + + Local obj = Nan::To(value).ToLocalChecked(); + + if (!Nan::Has(obj, Nan::New("height").ToLocalChecked()) + .FromMaybe(false)) + { + return false; + } + + if (!Nan::Has(obj, Nan::New("width").ToLocalChecked()) + .FromMaybe(false)) + { + return false; + } + + return true; + } + + wchar_t GetFirstChar(Local value) + { + wchar_t retVal = 0; + + if (!value->IsString()) + { + return retVal; + } + + Local str = Nan::To(value).ToLocalChecked(); + if (str->Length() == 0) + { + return retVal; + } + + String::Value val(v8::Isolate::GetCurrent(), str); + retVal = (*val)[0]; + return retVal; + } + + Local JsStringFromChar(wchar_t value) + { + wchar_t str[2]; + str[0] = value; + str[1] = L'\0'; + + return NewString(str); + } + + ::Windows::Foundation::HResult HResultFromJsInt32(int32_t value) + { + ::Windows::Foundation::HResult res; + res.Value = value; + return res; + } + + } // namespace Utils +} // namespace NodeRT diff --git a/desktop/addons/windows-pushnotifications/OpaqueWrapper.h b/desktop/addons/windows-pushnotifications/OpaqueWrapper.h new file mode 100644 --- /dev/null +++ b/desktop/addons/windows-pushnotifications/OpaqueWrapper.h @@ -0,0 +1,73 @@ +// Copyright (c) The NodeRT Contributors +// All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the ""License""); you may +// not use this file except in compliance with the License. You may obtain a +// copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS +// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY +// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +// MERCHANTABLITY OR NON-INFRINGEMENT. +// +// See the Apache Version 2.0 License for specific language governing +// permissions and limitations under the License. + +#pragma once + +#include +#include +#include +#include "NodeRTUtils.h" +#include "WrapperBase.h" +#include "nan.h" +#include "nan_object_wrap.h" + +namespace NodeRT +{ + class OpaqueWrapperInitializer; + + v8::Local CreateOpaqueWrapper(::Platform::Object ^ wintRtHandle); + + class OpaqueWrapper : public WrapperBase + { + public: + virtual ::Platform::Object ^ GetObjectInstance() const override + { + return _instance; + } + + static bool IsOpaqueWrapper(v8::Local value) + { + if (value.IsEmpty() || !value->IsObject()) + { + return false; + } + + v8::Local hiddenVal = NodeRT::Utils::GetHiddenValue( + value.As(), + Nan::New("__winrtOpaqueWrapper__").ToLocalChecked()); + + if (hiddenVal.IsEmpty() || !hiddenVal->IsBoolean()) + { + return false; + } + + return hiddenVal->IsTrue(); + } + + private: + OpaqueWrapper(::Platform::Object ^ instance) : _instance(instance) {} + + static void New(Nan::NAN_METHOD_ARGS_TYPE info); + static void Init(); + + private: + ::Platform::Object ^ _instance; + static Nan::Persistent s_constructorTemplate; + + friend OpaqueWrapperInitializer; + friend v8::Local CreateOpaqueWrapper(::Platform::Object ^ + wintRtInstance); + }; +} // namespace NodeRT diff --git a/desktop/addons/windows-pushnotifications/OpaqueWrapper.cpp b/desktop/addons/windows-pushnotifications/OpaqueWrapper.cpp new file mode 100644 --- /dev/null +++ b/desktop/addons/windows-pushnotifications/OpaqueWrapper.cpp @@ -0,0 +1,67 @@ +// Copyright (c) The NodeRT Contributors +// All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the ""License""); you may +// not use this file except in compliance with the License. You may obtain a +// copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS +// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY +// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +// MERCHANTABLITY OR NON-INFRINGEMENT. +// +// See the Apache Version 2.0 License for specific language governing permissions +// and limitations under the License. + +#include "OpaqueWrapper.h" +#include "NodeRtUtils.h" + +using v8::FunctionTemplate; +using v8::String; + +Nan::Persistent NodeRT::OpaqueWrapper::s_constructorTemplate; + +void NodeRT::OpaqueWrapper::New(Nan::NAN_METHOD_ARGS_TYPE info) +{ + NodeRT::Utils::SetHiddenValue(info.This(), Nan::New("__winrtOpaqueWrapper__").ToLocalChecked(), Nan::True()); + + info.GetReturnValue().Set(info.This()); +} + +void NodeRT::OpaqueWrapper::Init() +{ + Nan::HandleScope scope; + // Prepare constructor template + s_constructorTemplate.Reset(Nan::New(New)); + v8::Local localRef = Nan::New(s_constructorTemplate); + localRef->SetClassName(Nan::New("OpaqueWrapper").ToLocalChecked()); + localRef->InstanceTemplate()->SetInternalFieldCount(1); +} + +namespace NodeRT +{ + v8::Local CreateOpaqueWrapper(::Platform::Object ^ winRtInstance) + { + Nan::EscapableHandleScope scope; + if (winRtInstance == nullptr) + { + return scope.Escape(Nan::Undefined()); + } + + v8::Local args[] = {Nan::Undefined()}; + if (OpaqueWrapper::s_constructorTemplate.IsEmpty()) + { + OpaqueWrapper::Init(); + } + + v8::Local localRef = Nan::New(OpaqueWrapper::s_constructorTemplate); + v8::Local objectInstance = Nan::NewInstance(Nan::GetFunction(localRef).ToLocalChecked(), 0, args).ToLocalChecked(); + if (objectInstance.IsEmpty()) + { + return scope.Escape(Nan::Undefined()); + } + OpaqueWrapper *wrapperInstance = new OpaqueWrapper(winRtInstance); + wrapperInstance->Wrap(objectInstance); + return scope.Escape(objectInstance); + } +} diff --git a/desktop/addons/windows-pushnotifications/WrapperBase.h b/desktop/addons/windows-pushnotifications/WrapperBase.h new file mode 100644 --- /dev/null +++ b/desktop/addons/windows-pushnotifications/WrapperBase.h @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the ""License""); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS +// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY +// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +// MERCHANTABLITY OR NON-INFRINGEMENT. +// +// See the Apache Version 2.0 License for specific language governing +// permissions and limitations under the License. + +#pragma once +#include + +namespace NodeRT +{ + class WrapperBase : public Nan::ObjectWrap + { + public: + virtual ::Platform::Object ^ GetObjectInstance() const = 0; + }; +} // namespace NodeRT \ No newline at end of file diff --git a/desktop/addons/windows-pushnotifications/_nodert_generated.cpp b/desktop/addons/windows-pushnotifications/_nodert_generated.cpp new file mode 100644 --- /dev/null +++ b/desktop/addons/windows-pushnotifications/_nodert_generated.cpp @@ -0,0 +1,1662 @@ +// Copyright (c) The NodeRT Contributors +// All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the ""License""); you may +// not use this file except in compliance with the License. You may obtain a +// copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS +// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY +// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +// MERCHANTABLITY OR NON-INFRINGEMENT. +// +// See the Apache Version 2.0 License for specific language governing permissions +// and limitations under the License. + +// TODO: Verify that this is is still needed.. +#define NTDDI_VERSION 0x06010000 + +#include +#include "nan.h" +#include +#include +#include "CollectionsConverter.h" +#include "CollectionsWrap.h" +#include "node-async.h" +#include "NodeRtUtils.h" +#include "OpaqueWrapper.h" +#include "WrapperBase.h" + +#using < Microsoft.Windows.PushNotifications.WinMD> + +// this undefs fixes the issues of compiling Windows.Data.Json, Windows.Storag.FileProperties, and Windows.Stroage.Search +// Some of the node header files brings windows definitions with the same names as some of the WinRT methods +#undef DocumentProperties +#undef GetObject +#undef CreateEvent +#undef FindText +#undef SendMessage + +const char *REGISTRATION_TOKEN_MAP_PROPERTY_NAME = "__registrationTokenMap__"; + +using Nan::EscapableHandleScope; +using Nan::False; +using Nan::HandleScope; +using Nan::MaybeLocal; +using Nan::Null; +using Nan::Persistent; +using Nan::True; +using Nan::TryCatch; +using Nan::Undefined; +using v8::Array; +using v8::Boolean; +using v8::Date; +using v8::Function; +using v8::FunctionTemplate; +using v8::Integer; +using v8::Local; +using v8::Number; +using v8::Object; +using v8::Primitive; +using v8::PropertyAttribute; +using v8::String; +using v8::Value; +using namespace concurrency; + +namespace NodeRT +{ + namespace Microsoft + { + namespace Windows + { + namespace PushNotifications + { + v8::Local WrapPushNotificationChannel(::Microsoft::Windows::PushNotifications::PushNotificationChannel ^ wintRtInstance); + ::Microsoft::Windows::PushNotifications::PushNotificationChannel ^ UnwrapPushNotificationChannel(Local value); + + v8::Local WrapPushNotificationCreateChannelResult(::Microsoft::Windows::PushNotifications::PushNotificationCreateChannelResult ^ wintRtInstance); + ::Microsoft::Windows::PushNotifications::PushNotificationCreateChannelResult ^ UnwrapPushNotificationCreateChannelResult(Local value); + + v8::Local WrapPushNotificationManager(::Microsoft::Windows::PushNotifications::PushNotificationManager ^ wintRtInstance); + ::Microsoft::Windows::PushNotifications::PushNotificationManager ^ UnwrapPushNotificationManager(Local value); + + v8::Local WrapPushNotificationReceivedEventArgs(::Microsoft::Windows::PushNotifications::PushNotificationReceivedEventArgs ^ wintRtInstance); + ::Microsoft::Windows::PushNotifications::PushNotificationReceivedEventArgs ^ UnwrapPushNotificationReceivedEventArgs(Local value); + + static void InitPushNotificationChannelStatusEnum(const Local exports) + { + HandleScope scope; + + Local enumObject = Nan::New(); + + Nan::Set(exports, Nan::New("PushNotificationChannelStatus").ToLocalChecked(), enumObject); + Nan::Set(enumObject, Nan::New("inProgress").ToLocalChecked(), Nan::New(static_cast(::Microsoft::Windows::PushNotifications::PushNotificationChannelStatus::InProgress))); + Nan::Set(enumObject, Nan::New("inProgressRetry").ToLocalChecked(), Nan::New(static_cast(::Microsoft::Windows::PushNotifications::PushNotificationChannelStatus::InProgressRetry))); + Nan::Set(enumObject, Nan::New("completedSuccess").ToLocalChecked(), Nan::New(static_cast(::Microsoft::Windows::PushNotifications::PushNotificationChannelStatus::CompletedSuccess))); + Nan::Set(enumObject, Nan::New("completedFailure").ToLocalChecked(), Nan::New(static_cast(::Microsoft::Windows::PushNotifications::PushNotificationChannelStatus::CompletedFailure))); + } + + static bool IsPushNotificationCreateChannelStatusJsObject(Local value) + { + if (!value->IsObject()) + { + return false; + } + + Local symbol; + Local obj = Nan::To(value).ToLocalChecked(); + + symbol = Nan::New("status").ToLocalChecked(); + if (Nan::Has(obj, symbol).FromMaybe(false)) + { + if (!Nan::Get(obj, symbol).ToLocalChecked()->IsInt32()) + { + return false; + } + } + + symbol = Nan::New("extendedError").ToLocalChecked(); + if (Nan::Has(obj, symbol).FromMaybe(false)) + { + if (!NodeRT::Utils::IsWinRtWrapperOf<::Platform::Exception ^>(Nan::Get(obj, symbol).ToLocalChecked())) + { + return false; + } + } + + symbol = Nan::New("retryCount").ToLocalChecked(); + if (Nan::Has(obj, symbol).FromMaybe(false)) + { + if (!Nan::Get(obj, symbol).ToLocalChecked()->IsUint32()) + { + return false; + } + } + + return true; + } + + ::Microsoft::Windows::PushNotifications::PushNotificationCreateChannelStatus PushNotificationCreateChannelStatusFromJsObject(Local value) + { + HandleScope scope; + ::Microsoft::Windows::PushNotifications::PushNotificationCreateChannelStatus returnValue; + + if (!value->IsObject()) + { + Nan::ThrowError(Nan::TypeError(NodeRT::Utils::NewString(L"Unexpected type, expected an object"))); + return returnValue; + } + + Local obj = Nan::To(value).ToLocalChecked(); + Local symbol; + + symbol = Nan::New("status").ToLocalChecked(); + if (Nan::Has(obj, symbol).FromMaybe(false)) + { + returnValue.status = static_cast<::Microsoft::Windows::PushNotifications::PushNotificationChannelStatus>(Nan::To(Nan::Get(obj, symbol).ToLocalChecked()).FromMaybe(0)); + } + + symbol = Nan::New("extendedError").ToLocalChecked(); + if (Nan::Has(obj, symbol).FromMaybe(false)) + { + returnValue.extendedError = NodeRT::Utils::HResultFromJsInt32(Nan::To(Nan::Get(obj, symbol).ToLocalChecked()).FromMaybe(0)); + } + + symbol = Nan::New("retryCount").ToLocalChecked(); + if (Nan::Has(obj, symbol).FromMaybe(false)) + { + returnValue.retryCount = static_cast(Nan::To(Nan::Get(obj, symbol).ToLocalChecked()).FromMaybe(0)); + } + + return returnValue; + } + + Local PushNotificationCreateChannelStatusToJsObject(::Microsoft::Windows::PushNotifications::PushNotificationCreateChannelStatus value) + { + EscapableHandleScope scope; + + Local obj = Nan::New(); + + Nan::Set(obj, Nan::New("status").ToLocalChecked(), Nan::New(static_cast(value.status))); + Nan::Set(obj, Nan::New("extendedError").ToLocalChecked(), Nan::New(value.extendedError.Value)); + Nan::Set(obj, Nan::New("retryCount").ToLocalChecked(), Nan::New(value.retryCount)); + + return scope.Escape(obj); + } + static bool IsPushNotificationsContractJsObject(Local value) + { + if (!value->IsObject()) + { + return false; + } + + Local symbol; + Local obj = Nan::To(value).ToLocalChecked(); + + return true; + } + + ::Microsoft::Windows::PushNotifications::PushNotificationsContract PushNotificationsContractFromJsObject(Local value) + { + HandleScope scope; + ::Microsoft::Windows::PushNotifications::PushNotificationsContract returnValue; + + if (!value->IsObject()) + { + Nan::ThrowError(Nan::TypeError(NodeRT::Utils::NewString(L"Unexpected type, expected an object"))); + return returnValue; + } + + Local obj = Nan::To(value).ToLocalChecked(); + Local symbol; + + return returnValue; + } + + Local PushNotificationsContractToJsObject(::Microsoft::Windows::PushNotifications::PushNotificationsContract value) + { + EscapableHandleScope scope; + + Local obj = Nan::New(); + + return scope.Escape(obj); + } + + class PushNotificationChannel : public WrapperBase + { + public: + static void Init(const Local exports) + { + HandleScope scope; + + Local localRef = Nan::New(New); + s_constructorTemplate.Reset(localRef); + localRef->SetClassName(Nan::New("PushNotificationChannel").ToLocalChecked()); + localRef->InstanceTemplate()->SetInternalFieldCount(1); + + Nan::SetPrototypeMethod(localRef, "close", Close); + + Nan::SetAccessor(localRef->PrototypeTemplate(), Nan::New("expirationTime").ToLocalChecked(), ExpirationTimeGetter); + Nan::SetAccessor(localRef->PrototypeTemplate(), Nan::New("uri").ToLocalChecked(), UriGetter); + + Local constructor = Nan::To(Nan::GetFunction(localRef).ToLocalChecked()).ToLocalChecked(); + Nan::SetMethod(constructor, "castFrom", CastFrom); + + Nan::Set(exports, Nan::New("PushNotificationChannel").ToLocalChecked(), constructor); + } + + virtual ::Platform::Object ^ GetObjectInstance() const override + { + return _instance; + } + + private: + PushNotificationChannel(::Microsoft::Windows::PushNotifications::PushNotificationChannel ^ instance) + { + _instance = instance; + } + + static void New(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + Local localRef = Nan::New(s_constructorTemplate); + + // in case the constructor was called without the new operator + if (!localRef->HasInstance(info.This())) + { + if (info.Length() > 0) + { + std::unique_ptr[]> constructorArgs(new Local[info.Length()]); + + Local *argsPtr = constructorArgs.get(); + for (int i = 0; i < info.Length(); i++) + { + argsPtr[i] = info[i]; + } + + MaybeLocal res = Nan::NewInstance(Nan::GetFunction(localRef).ToLocalChecked(), info.Length(), constructorArgs.get()); + if (res.IsEmpty()) + { + return; + } + + info.GetReturnValue().Set(res.ToLocalChecked()); + return; + } + else + { + MaybeLocal res = Nan::NewInstance(Nan::GetFunction(localRef).ToLocalChecked(), info.Length(), nullptr); + + if (res.IsEmpty()) + { + return; + } + + info.GetReturnValue().Set(res.ToLocalChecked()); + return; + } + } + + ::Microsoft::Windows::PushNotifications::PushNotificationChannel ^ winRtInstance; + + if (info.Length() == 1 && OpaqueWrapper::IsOpaqueWrapper(info[0]) && + NodeRT::Utils::IsWinRtWrapperOf<::Microsoft::Windows::PushNotifications::PushNotificationChannel ^>(info[0])) + { + try + { + winRtInstance = (::Microsoft::Windows::PushNotifications::PushNotificationChannel ^) NodeRT::Utils::GetObjectInstance(info[0]); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString(L"Invalid arguments, no suitable constructor found"))); + return; + } + + NodeRT::Utils::SetHiddenValue(info.This(), Nan::New("__winRtInstance__").ToLocalChecked(), True()); + + PushNotificationChannel *wrapperInstance = new PushNotificationChannel(winRtInstance); + wrapperInstance->Wrap(info.This()); + + info.GetReturnValue().Set(info.This()); + } + + static void CastFrom(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + if (info.Length() < 1 || !NodeRT::Utils::IsWinRtWrapperOf<::Microsoft::Windows::PushNotifications::PushNotificationChannel ^>(info[0])) + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString(L"Invalid arguments, no object provided, or given object could not be casted to requested type"))); + return; + } + + ::Microsoft::Windows::PushNotifications::PushNotificationChannel ^ winRtInstance; + try + { + winRtInstance = (::Microsoft::Windows::PushNotifications::PushNotificationChannel ^) NodeRT::Utils::GetObjectInstance(info[0]); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + + info.GetReturnValue().Set(WrapPushNotificationChannel(winRtInstance)); + } + + static void Close(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf<::Microsoft::Windows::PushNotifications::PushNotificationChannel ^>(info.This())) + { + return; + } + + PushNotificationChannel *wrapper = PushNotificationChannel::Unwrap(info.This()); + + if (info.Length() == 0) + { + try + { + wrapper->_instance->Close(); + return; + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString(L"Bad arguments: no suitable overload found"))); + return; + } + } + + static void ExpirationTimeGetter(Local property, const Nan::PropertyCallbackInfo &info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf<::Microsoft::Windows::PushNotifications::PushNotificationChannel ^>(info.This())) + { + return; + } + + PushNotificationChannel *wrapper = PushNotificationChannel::Unwrap(info.This()); + + try + { + ::Windows::Foundation::DateTime result = wrapper->_instance->ExpirationTime; + info.GetReturnValue().Set(NodeRT::Utils::DateTimeToJS(result)); + return; + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + + static void UriGetter(Local property, const Nan::PropertyCallbackInfo &info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf<::Microsoft::Windows::PushNotifications::PushNotificationChannel ^>(info.This())) + { + return; + } + + PushNotificationChannel *wrapper = PushNotificationChannel::Unwrap(info.This()); + + try + { + ::Windows::Foundation::Uri ^ result = wrapper->_instance->Uri; + info.GetReturnValue().Set(NodeRT::Utils::CreateExternalWinRTObject("Windows.Foundation", "Uri", result)); + return; + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + + private: + ::Microsoft::Windows::PushNotifications::PushNotificationChannel ^ _instance; + static Persistent s_constructorTemplate; + + friend v8::Local WrapPushNotificationChannel(::Microsoft::Windows::PushNotifications::PushNotificationChannel ^ wintRtInstance); + friend ::Microsoft::Windows::PushNotifications::PushNotificationChannel ^ UnwrapPushNotificationChannel(Local value); + }; + + Persistent PushNotificationChannel::s_constructorTemplate; + + v8::Local WrapPushNotificationChannel(::Microsoft::Windows::PushNotifications::PushNotificationChannel ^ winRtInstance) + { + EscapableHandleScope scope; + + if (winRtInstance == nullptr) + { + return scope.Escape(Undefined()); + } + + Local opaqueWrapper = CreateOpaqueWrapper(winRtInstance); + Local args[] = {opaqueWrapper}; + Local localRef = Nan::New(PushNotificationChannel::s_constructorTemplate); + return scope.Escape(Nan::NewInstance(Nan::GetFunction(localRef).ToLocalChecked(), _countof(args), args).ToLocalChecked()); + } + + ::Microsoft::Windows::PushNotifications::PushNotificationChannel ^ UnwrapPushNotificationChannel(Local value) { + return PushNotificationChannel::Unwrap(Nan::To(value).ToLocalChecked())->_instance; + } + + void InitPushNotificationChannel(Local exports) + { + PushNotificationChannel::Init(exports); + } + + class PushNotificationCreateChannelResult : public WrapperBase + { + public: + static void Init(const Local exports) + { + HandleScope scope; + + Local localRef = Nan::New(New); + s_constructorTemplate.Reset(localRef); + localRef->SetClassName(Nan::New("PushNotificationCreateChannelResult").ToLocalChecked()); + localRef->InstanceTemplate()->SetInternalFieldCount(1); + + Nan::SetAccessor(localRef->PrototypeTemplate(), Nan::New("channel").ToLocalChecked(), ChannelGetter); + Nan::SetAccessor(localRef->PrototypeTemplate(), Nan::New("extendedError").ToLocalChecked(), ExtendedErrorGetter); + Nan::SetAccessor(localRef->PrototypeTemplate(), Nan::New("status").ToLocalChecked(), StatusGetter); + + Local constructor = Nan::To(Nan::GetFunction(localRef).ToLocalChecked()).ToLocalChecked(); + Nan::SetMethod(constructor, "castFrom", CastFrom); + + Nan::Set(exports, Nan::New("PushNotificationCreateChannelResult").ToLocalChecked(), constructor); + } + + virtual ::Platform::Object ^ GetObjectInstance() const override + { + return _instance; + } + + private: + PushNotificationCreateChannelResult(::Microsoft::Windows::PushNotifications::PushNotificationCreateChannelResult ^ instance) + { + _instance = instance; + } + + static void New(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + Local localRef = Nan::New(s_constructorTemplate); + + // in case the constructor was called without the new operator + if (!localRef->HasInstance(info.This())) + { + if (info.Length() > 0) + { + std::unique_ptr[]> constructorArgs(new Local[info.Length()]); + + Local *argsPtr = constructorArgs.get(); + for (int i = 0; i < info.Length(); i++) + { + argsPtr[i] = info[i]; + } + + MaybeLocal res = Nan::NewInstance(Nan::GetFunction(localRef).ToLocalChecked(), info.Length(), constructorArgs.get()); + if (res.IsEmpty()) + { + return; + } + + info.GetReturnValue().Set(res.ToLocalChecked()); + return; + } + else + { + MaybeLocal res = Nan::NewInstance(Nan::GetFunction(localRef).ToLocalChecked(), info.Length(), nullptr); + + if (res.IsEmpty()) + { + return; + } + + info.GetReturnValue().Set(res.ToLocalChecked()); + return; + } + } + + ::Microsoft::Windows::PushNotifications::PushNotificationCreateChannelResult ^ winRtInstance; + + if (info.Length() == 1 && OpaqueWrapper::IsOpaqueWrapper(info[0]) && + NodeRT::Utils::IsWinRtWrapperOf<::Microsoft::Windows::PushNotifications::PushNotificationCreateChannelResult ^>(info[0])) + { + try + { + winRtInstance = (::Microsoft::Windows::PushNotifications::PushNotificationCreateChannelResult ^) NodeRT::Utils::GetObjectInstance(info[0]); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString(L"Invalid arguments, no suitable constructor found"))); + return; + } + + NodeRT::Utils::SetHiddenValue(info.This(), Nan::New("__winRtInstance__").ToLocalChecked(), True()); + + PushNotificationCreateChannelResult *wrapperInstance = new PushNotificationCreateChannelResult(winRtInstance); + wrapperInstance->Wrap(info.This()); + + info.GetReturnValue().Set(info.This()); + } + + static void CastFrom(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + if (info.Length() < 1 || !NodeRT::Utils::IsWinRtWrapperOf<::Microsoft::Windows::PushNotifications::PushNotificationCreateChannelResult ^>(info[0])) + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString(L"Invalid arguments, no object provided, or given object could not be casted to requested type"))); + return; + } + + ::Microsoft::Windows::PushNotifications::PushNotificationCreateChannelResult ^ winRtInstance; + try + { + winRtInstance = (::Microsoft::Windows::PushNotifications::PushNotificationCreateChannelResult ^) NodeRT::Utils::GetObjectInstance(info[0]); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + + info.GetReturnValue().Set(WrapPushNotificationCreateChannelResult(winRtInstance)); + } + + static void ChannelGetter(Local property, const Nan::PropertyCallbackInfo &info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf<::Microsoft::Windows::PushNotifications::PushNotificationCreateChannelResult ^>(info.This())) + { + return; + } + + PushNotificationCreateChannelResult *wrapper = PushNotificationCreateChannelResult::Unwrap(info.This()); + + try + { + ::Microsoft::Windows::PushNotifications::PushNotificationChannel ^ result = wrapper->_instance->Channel; + info.GetReturnValue().Set(WrapPushNotificationChannel(result)); + return; + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + + static void ExtendedErrorGetter(Local property, const Nan::PropertyCallbackInfo &info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf<::Microsoft::Windows::PushNotifications::PushNotificationCreateChannelResult ^>(info.This())) + { + return; + } + + PushNotificationCreateChannelResult *wrapper = PushNotificationCreateChannelResult::Unwrap(info.This()); + + try + { + ::Windows::Foundation::HResult result = wrapper->_instance->ExtendedError; + info.GetReturnValue().Set(Nan::New(result.Value)); + return; + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + + static void StatusGetter(Local property, const Nan::PropertyCallbackInfo &info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf<::Microsoft::Windows::PushNotifications::PushNotificationCreateChannelResult ^>(info.This())) + { + return; + } + + PushNotificationCreateChannelResult *wrapper = PushNotificationCreateChannelResult::Unwrap(info.This()); + + try + { + ::Microsoft::Windows::PushNotifications::PushNotificationChannelStatus result = wrapper->_instance->Status; + info.GetReturnValue().Set(Nan::New(static_cast(result))); + return; + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + + private: + ::Microsoft::Windows::PushNotifications::PushNotificationCreateChannelResult ^ _instance; + static Persistent s_constructorTemplate; + + friend v8::Local WrapPushNotificationCreateChannelResult(::Microsoft::Windows::PushNotifications::PushNotificationCreateChannelResult ^ wintRtInstance); + friend ::Microsoft::Windows::PushNotifications::PushNotificationCreateChannelResult ^ UnwrapPushNotificationCreateChannelResult(Local value); + }; + + Persistent PushNotificationCreateChannelResult::s_constructorTemplate; + + v8::Local WrapPushNotificationCreateChannelResult(::Microsoft::Windows::PushNotifications::PushNotificationCreateChannelResult ^ winRtInstance) + { + EscapableHandleScope scope; + + if (winRtInstance == nullptr) + { + return scope.Escape(Undefined()); + } + + Local opaqueWrapper = CreateOpaqueWrapper(winRtInstance); + Local args[] = {opaqueWrapper}; + Local localRef = Nan::New(PushNotificationCreateChannelResult::s_constructorTemplate); + return scope.Escape(Nan::NewInstance(Nan::GetFunction(localRef).ToLocalChecked(), _countof(args), args).ToLocalChecked()); + } + + ::Microsoft::Windows::PushNotifications::PushNotificationCreateChannelResult ^ UnwrapPushNotificationCreateChannelResult(Local value) { + return PushNotificationCreateChannelResult::Unwrap(Nan::To(value).ToLocalChecked())->_instance; + } + + void InitPushNotificationCreateChannelResult(Local exports) + { + PushNotificationCreateChannelResult::Init(exports); + } + + class PushNotificationManager : public WrapperBase + { + public: + static void Init(const Local exports) + { + HandleScope scope; + + Local localRef = Nan::New(New); + s_constructorTemplate.Reset(localRef); + localRef->SetClassName(Nan::New("PushNotificationManager").ToLocalChecked()); + localRef->InstanceTemplate()->SetInternalFieldCount(1); + + Local func; + Local funcTemplate; + + Nan::SetPrototypeMethod(localRef, "register", Register); + Nan::SetPrototypeMethod(localRef, "unregister", Unregister); + Nan::SetPrototypeMethod(localRef, "unregisterAll", UnregisterAll); + + Nan::SetPrototypeMethod(localRef, "createChannelAsync", CreateChannelAsync); + + Nan::SetPrototypeMethod(localRef, "addListener", AddListener); + Nan::SetPrototypeMethod(localRef, "on", AddListener); + Nan::SetPrototypeMethod(localRef, "removeListener", RemoveListener); + Nan::SetPrototypeMethod(localRef, "off", RemoveListener); + + Local constructor = Nan::To(Nan::GetFunction(localRef).ToLocalChecked()).ToLocalChecked(); + Nan::SetMethod(constructor, "castFrom", CastFrom); + + Nan::SetMethod(constructor, "isSupported", IsSupported); + Nan::SetAccessor(constructor, Nan::New("default").ToLocalChecked(), DefaultGetter); + + Nan::Set(exports, Nan::New("PushNotificationManager").ToLocalChecked(), constructor); + } + + virtual ::Platform::Object ^ GetObjectInstance() const override + { + return _instance; + } + + private: + PushNotificationManager(::Microsoft::Windows::PushNotifications::PushNotificationManager ^ instance) + { + _instance = instance; + } + + static void New(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + Local localRef = Nan::New(s_constructorTemplate); + + // in case the constructor was called without the new operator + if (!localRef->HasInstance(info.This())) + { + if (info.Length() > 0) + { + std::unique_ptr[]> constructorArgs(new Local[info.Length()]); + + Local *argsPtr = constructorArgs.get(); + for (int i = 0; i < info.Length(); i++) + { + argsPtr[i] = info[i]; + } + + MaybeLocal res = Nan::NewInstance(Nan::GetFunction(localRef).ToLocalChecked(), info.Length(), constructorArgs.get()); + if (res.IsEmpty()) + { + return; + } + + info.GetReturnValue().Set(res.ToLocalChecked()); + return; + } + else + { + MaybeLocal res = Nan::NewInstance(Nan::GetFunction(localRef).ToLocalChecked(), info.Length(), nullptr); + + if (res.IsEmpty()) + { + return; + } + + info.GetReturnValue().Set(res.ToLocalChecked()); + return; + } + } + + ::Microsoft::Windows::PushNotifications::PushNotificationManager ^ winRtInstance; + + if (info.Length() == 1 && OpaqueWrapper::IsOpaqueWrapper(info[0]) && + NodeRT::Utils::IsWinRtWrapperOf<::Microsoft::Windows::PushNotifications::PushNotificationManager ^>(info[0])) + { + try + { + winRtInstance = (::Microsoft::Windows::PushNotifications::PushNotificationManager ^) NodeRT::Utils::GetObjectInstance(info[0]); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString(L"Invalid arguments, no suitable constructor found"))); + return; + } + + NodeRT::Utils::SetHiddenValue(info.This(), Nan::New("__winRtInstance__").ToLocalChecked(), True()); + + PushNotificationManager *wrapperInstance = new PushNotificationManager(winRtInstance); + wrapperInstance->Wrap(info.This()); + + info.GetReturnValue().Set(info.This()); + } + + static void CastFrom(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + if (info.Length() < 1 || !NodeRT::Utils::IsWinRtWrapperOf<::Microsoft::Windows::PushNotifications::PushNotificationManager ^>(info[0])) + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString(L"Invalid arguments, no object provided, or given object could not be casted to requested type"))); + return; + } + + ::Microsoft::Windows::PushNotifications::PushNotificationManager ^ winRtInstance; + try + { + winRtInstance = (::Microsoft::Windows::PushNotifications::PushNotificationManager ^) NodeRT::Utils::GetObjectInstance(info[0]); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + + info.GetReturnValue().Set(WrapPushNotificationManager(winRtInstance)); + } + + static void CreateChannelAsync(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf<::Microsoft::Windows::PushNotifications::PushNotificationManager ^>(info.This())) + { + return; + } + + if (info.Length() == 0 || !info[info.Length() - 1]->IsFunction()) + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString(L"Bad arguments: No callback was given"))); + return; + } + + PushNotificationManager *wrapper = PushNotificationManager::Unwrap(info.This()); + + ::Windows::Foundation::IAsyncOperationWithProgress<::Microsoft::Windows::PushNotifications::PushNotificationCreateChannelResult ^, ::Microsoft::Windows::PushNotifications::PushNotificationCreateChannelStatus> ^ op; + + if (info.Length() == 2 && NodeRT::Utils::IsGuid(info[0])) + { + try + { + ::Platform::Guid arg0 = NodeRT::Utils::GuidFromJs(info[0]); + + op = wrapper->_instance->CreateChannelAsync(arg0); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString(L"Bad arguments: no suitable overload found"))); + return; + } + + auto opTask = create_task(op); + uv_async_t *asyncToken = NodeUtils::Async::GetAsyncToken(info[info.Length() - 1].As()); + + opTask.then([asyncToken](task<::Microsoft::Windows::PushNotifications::PushNotificationCreateChannelResult ^> t) + { + try { + auto result = t.get(); + NodeUtils::Async::RunCallbackOnMain(asyncToken, [result](NodeUtils::InvokeCallbackDelegate invokeCallback) { + + + Local error; + Local arg1; + { + TryCatch tryCatch; + arg1 = WrapPushNotificationCreateChannelResult(result); + if (tryCatch.HasCaught()) + { + error = Nan::To(tryCatch.Exception()).ToLocalChecked(); + } + else + { + error = Undefined(); + } + if (arg1.IsEmpty()) arg1 = Undefined(); + } + Local args[] = {error, arg1}; + + + invokeCallback(_countof(args), args); + }); + } catch (Platform::Exception^ exception) { + NodeUtils::Async::RunCallbackOnMain(asyncToken, [exception](NodeUtils::InvokeCallbackDelegate invokeCallback) { + Local error = NodeRT::Utils::WinRtExceptionToJsError(exception); + + Local args[] = {error}; + invokeCallback(_countof(args), args); + }); + } }); + } + + static void Register(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf<::Microsoft::Windows::PushNotifications::PushNotificationManager ^>(info.This())) + { + return; + } + + PushNotificationManager *wrapper = PushNotificationManager::Unwrap(info.This()); + + if (info.Length() == 0) + { + try + { + wrapper->_instance->Register(); + return; + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString(L"Bad arguments: no suitable overload found"))); + return; + } + } + static void Unregister(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf<::Microsoft::Windows::PushNotifications::PushNotificationManager ^>(info.This())) + { + return; + } + + PushNotificationManager *wrapper = PushNotificationManager::Unwrap(info.This()); + + if (info.Length() == 0) + { + try + { + wrapper->_instance->Unregister(); + return; + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString(L"Bad arguments: no suitable overload found"))); + return; + } + } + static void UnregisterAll(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf<::Microsoft::Windows::PushNotifications::PushNotificationManager ^>(info.This())) + { + return; + } + + PushNotificationManager *wrapper = PushNotificationManager::Unwrap(info.This()); + + if (info.Length() == 0) + { + try + { + wrapper->_instance->UnregisterAll(); + return; + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString(L"Bad arguments: no suitable overload found"))); + return; + } + } + + static void IsSupported(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (info.Length() == 0) + { + try + { + bool result; + result = ::Microsoft::Windows::PushNotifications::PushNotificationManager::IsSupported(); + info.GetReturnValue().Set(Nan::New(result)); + return; + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString(L"Bad arguments: no suitable overload found"))); + return; + } + } + + static void DefaultGetter(Local property, const Nan::PropertyCallbackInfo &info) + { + HandleScope scope; + + try + { + ::Microsoft::Windows::PushNotifications::PushNotificationManager ^ result = ::Microsoft::Windows::PushNotifications::PushNotificationManager::Default; + info.GetReturnValue().Set(WrapPushNotificationManager(result)); + return; + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + + static void AddListener(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (info.Length() < 2 || !info[0]->IsString() || !info[1]->IsFunction()) + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString(L"wrong arguments, expected arguments are eventName(string),callback(function)"))); + return; + } + + String::Value eventName(v8::Isolate::GetCurrent(), info[0]); + auto str = *eventName; + + Local callback = info[1].As(); + + ::Windows::Foundation::EventRegistrationToken registrationToken; + if (NodeRT::Utils::CaseInsenstiveEquals(L"pushReceived", str)) + { + if (!NodeRT::Utils::IsWinRtWrapperOf<::Microsoft::Windows::PushNotifications::PushNotificationManager ^>(info.This())) + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString(L"The caller of this method isn't of the expected type or internal WinRt object was disposed"))); + return; + } + PushNotificationManager *wrapper = PushNotificationManager::Unwrap(info.This()); + + try + { + Persistent *perstPtr = new Persistent(); + perstPtr->Reset(NodeRT::Utils::CreateCallbackObjectInDomain(callback)); + std::shared_ptr> callbackObjPtr(perstPtr, + [](Persistent *ptr) + { + NodeUtils::Async::RunOnMain([ptr]() + { + ptr->Reset(); + delete ptr; }); + }); + + registrationToken = wrapper->_instance->PushReceived::add( + ref new ::Windows::Foundation::TypedEventHandler<::Microsoft::Windows::PushNotifications::PushNotificationManager ^, ::Microsoft::Windows::PushNotifications::PushNotificationReceivedEventArgs ^>( + [callbackObjPtr](::Microsoft::Windows::PushNotifications::PushNotificationManager ^ arg0, ::Microsoft::Windows::PushNotifications::PushNotificationReceivedEventArgs ^ arg1) + { + NodeUtils::Async::RunOnMain([callbackObjPtr, arg0, arg1]() + { + HandleScope scope; + + + Local wrappedArg0; + Local wrappedArg1; + + { + TryCatch tryCatch; + + + wrappedArg0 = WrapPushNotificationManager(arg0); + wrappedArg1 = WrapPushNotificationReceivedEventArgs(arg1); + + + if (wrappedArg0.IsEmpty()) wrappedArg0 = Undefined(); + if (wrappedArg1.IsEmpty()) wrappedArg1 = Undefined(); + } + + Local args[] = { wrappedArg0, wrappedArg1 }; + Local callbackObjLocalRef = Nan::New(*callbackObjPtr); + NodeRT::Utils::CallCallbackInDomain(callbackObjLocalRef, _countof(args), args); }); + })); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(String::Concat(v8::Isolate::GetCurrent(), NodeRT::Utils::NewString(L"given event name isn't supported: "), info[0].As()))); + return; + } + + Local tokenMapVal = NodeRT::Utils::GetHiddenValue(callback, Nan::New(REGISTRATION_TOKEN_MAP_PROPERTY_NAME).ToLocalChecked()); + Local tokenMap; + + if (tokenMapVal.IsEmpty() || Nan::Equals(tokenMapVal, Undefined()).FromMaybe(false)) + { + tokenMap = Nan::New(); + NodeRT::Utils::SetHiddenValueWithObject(callback, Nan::New(REGISTRATION_TOKEN_MAP_PROPERTY_NAME).ToLocalChecked(), tokenMap); + } + else + { + tokenMap = Nan::To(tokenMapVal).ToLocalChecked(); + } + + Nan::Set(tokenMap, info[0], CreateOpaqueWrapper(::Windows::Foundation::PropertyValue::CreateInt64(registrationToken.Value))); + } + + static void RemoveListener(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (info.Length() < 2 || !info[0]->IsString() || !info[1]->IsFunction()) + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString(L"wrong arguments, expected a string and a callback"))); + return; + } + + String::Value eventName(v8::Isolate::GetCurrent(), info[0]); + auto str = *eventName; + + if ((!NodeRT::Utils::CaseInsenstiveEquals(L"pushReceived", str))) + { + Nan::ThrowError(Nan::Error(String::Concat(v8::Isolate::GetCurrent(), NodeRT::Utils::NewString(L"given event name isn't supported: "), info[0].As()))); + return; + } + + Local callback = info[1].As(); + Local tokenMap = NodeRT::Utils::GetHiddenValue(callback, Nan::New(REGISTRATION_TOKEN_MAP_PROPERTY_NAME).ToLocalChecked()); + + if (tokenMap.IsEmpty() || Nan::Equals(tokenMap, Undefined()).FromMaybe(false)) + { + return; + } + + Local opaqueWrapperObj = Nan::Get(Nan::To(tokenMap).ToLocalChecked(), info[0]).ToLocalChecked(); + + if (opaqueWrapperObj.IsEmpty() || Nan::Equals(opaqueWrapperObj, Undefined()).FromMaybe(false)) + { + return; + } + + OpaqueWrapper *opaqueWrapper = OpaqueWrapper::Unwrap(opaqueWrapperObj.As()); + + long long tokenValue = (long long)opaqueWrapper->GetObjectInstance(); + ::Windows::Foundation::EventRegistrationToken registrationToken; + registrationToken.Value = tokenValue; + + try + { + if (NodeRT::Utils::CaseInsenstiveEquals(L"pushReceived", str)) + { + if (!NodeRT::Utils::IsWinRtWrapperOf<::Microsoft::Windows::PushNotifications::PushNotificationManager ^>(info.This())) + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString(L"The caller of this method isn't of the expected type or internal WinRt object was disposed"))); + return; + } + PushNotificationManager *wrapper = PushNotificationManager::Unwrap(info.This()); + wrapper->_instance->PushReceived::remove(registrationToken); + } + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + } + + Nan::Delete(Nan::To(tokenMap).ToLocalChecked(), Nan::To(info[0]).ToLocalChecked()); + } + + private: + ::Microsoft::Windows::PushNotifications::PushNotificationManager ^ _instance; + static Persistent s_constructorTemplate; + + friend v8::Local WrapPushNotificationManager(::Microsoft::Windows::PushNotifications::PushNotificationManager ^ wintRtInstance); + friend ::Microsoft::Windows::PushNotifications::PushNotificationManager ^ UnwrapPushNotificationManager(Local value); + }; + + Persistent PushNotificationManager::s_constructorTemplate; + + v8::Local WrapPushNotificationManager(::Microsoft::Windows::PushNotifications::PushNotificationManager ^ winRtInstance) + { + EscapableHandleScope scope; + + if (winRtInstance == nullptr) + { + return scope.Escape(Undefined()); + } + + Local opaqueWrapper = CreateOpaqueWrapper(winRtInstance); + Local args[] = {opaqueWrapper}; + Local localRef = Nan::New(PushNotificationManager::s_constructorTemplate); + return scope.Escape(Nan::NewInstance(Nan::GetFunction(localRef).ToLocalChecked(), _countof(args), args).ToLocalChecked()); + } + + ::Microsoft::Windows::PushNotifications::PushNotificationManager ^ UnwrapPushNotificationManager(Local value) { + return PushNotificationManager::Unwrap(Nan::To(value).ToLocalChecked())->_instance; + } + + void InitPushNotificationManager(Local exports) + { + PushNotificationManager::Init(exports); + } + + class PushNotificationReceivedEventArgs : public WrapperBase + { + public: + static void Init(const Local exports) + { + HandleScope scope; + + Local localRef = Nan::New(New); + s_constructorTemplate.Reset(localRef); + localRef->SetClassName(Nan::New("PushNotificationReceivedEventArgs").ToLocalChecked()); + localRef->InstanceTemplate()->SetInternalFieldCount(1); + + Nan::SetPrototypeMethod(localRef, "getDeferral", GetDeferral); + + Nan::SetPrototypeMethod(localRef, "addListener", AddListener); + Nan::SetPrototypeMethod(localRef, "on", AddListener); + Nan::SetPrototypeMethod(localRef, "removeListener", RemoveListener); + Nan::SetPrototypeMethod(localRef, "off", RemoveListener); + + Nan::SetAccessor(localRef->PrototypeTemplate(), Nan::New("payload").ToLocalChecked(), PayloadGetter); + + Local constructor = Nan::To(Nan::GetFunction(localRef).ToLocalChecked()).ToLocalChecked(); + Nan::SetMethod(constructor, "castFrom", CastFrom); + + Nan::Set(exports, Nan::New("PushNotificationReceivedEventArgs").ToLocalChecked(), constructor); + } + + virtual ::Platform::Object ^ GetObjectInstance() const override + { + return _instance; + } + + private: + PushNotificationReceivedEventArgs(::Microsoft::Windows::PushNotifications::PushNotificationReceivedEventArgs ^ instance) + { + _instance = instance; + } + + static void New(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + Local localRef = Nan::New(s_constructorTemplate); + + // in case the constructor was called without the new operator + if (!localRef->HasInstance(info.This())) + { + if (info.Length() > 0) + { + std::unique_ptr[]> constructorArgs(new Local[info.Length()]); + + Local *argsPtr = constructorArgs.get(); + for (int i = 0; i < info.Length(); i++) + { + argsPtr[i] = info[i]; + } + + MaybeLocal res = Nan::NewInstance(Nan::GetFunction(localRef).ToLocalChecked(), info.Length(), constructorArgs.get()); + if (res.IsEmpty()) + { + return; + } + + info.GetReturnValue().Set(res.ToLocalChecked()); + return; + } + else + { + MaybeLocal res = Nan::NewInstance(Nan::GetFunction(localRef).ToLocalChecked(), info.Length(), nullptr); + + if (res.IsEmpty()) + { + return; + } + + info.GetReturnValue().Set(res.ToLocalChecked()); + return; + } + } + + ::Microsoft::Windows::PushNotifications::PushNotificationReceivedEventArgs ^ winRtInstance; + + if (info.Length() == 1 && OpaqueWrapper::IsOpaqueWrapper(info[0]) && + NodeRT::Utils::IsWinRtWrapperOf<::Microsoft::Windows::PushNotifications::PushNotificationReceivedEventArgs ^>(info[0])) + { + try + { + winRtInstance = (::Microsoft::Windows::PushNotifications::PushNotificationReceivedEventArgs ^) NodeRT::Utils::GetObjectInstance(info[0]); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString(L"Invalid arguments, no suitable constructor found"))); + return; + } + + NodeRT::Utils::SetHiddenValue(info.This(), Nan::New("__winRtInstance__").ToLocalChecked(), True()); + + PushNotificationReceivedEventArgs *wrapperInstance = new PushNotificationReceivedEventArgs(winRtInstance); + wrapperInstance->Wrap(info.This()); + + info.GetReturnValue().Set(info.This()); + } + + static void CastFrom(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + if (info.Length() < 1 || !NodeRT::Utils::IsWinRtWrapperOf<::Microsoft::Windows::PushNotifications::PushNotificationReceivedEventArgs ^>(info[0])) + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString(L"Invalid arguments, no object provided, or given object could not be casted to requested type"))); + return; + } + + ::Microsoft::Windows::PushNotifications::PushNotificationReceivedEventArgs ^ winRtInstance; + try + { + winRtInstance = (::Microsoft::Windows::PushNotifications::PushNotificationReceivedEventArgs ^) NodeRT::Utils::GetObjectInstance(info[0]); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + + info.GetReturnValue().Set(WrapPushNotificationReceivedEventArgs(winRtInstance)); + } + + static void GetDeferral(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf<::Microsoft::Windows::PushNotifications::PushNotificationReceivedEventArgs ^>(info.This())) + { + return; + } + + PushNotificationReceivedEventArgs *wrapper = PushNotificationReceivedEventArgs::Unwrap(info.This()); + + if (info.Length() == 0) + { + try + { + ::Windows::ApplicationModel::Background::BackgroundTaskDeferral ^ result; + result = wrapper->_instance->GetDeferral(); + info.GetReturnValue().Set(NodeRT::Utils::CreateExternalWinRTObject("Windows.ApplicationModel.Background", "BackgroundTaskDeferral", result)); + return; + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString(L"Bad arguments: no suitable overload found"))); + return; + } + } + + static void PayloadGetter(Local property, const Nan::PropertyCallbackInfo &info) + { + HandleScope scope; + + if (!NodeRT::Utils::IsWinRtWrapperOf<::Microsoft::Windows::PushNotifications::PushNotificationReceivedEventArgs ^>(info.This())) + { + return; + } + + PushNotificationReceivedEventArgs *wrapper = PushNotificationReceivedEventArgs::Unwrap(info.This()); + + try + { + ::Platform::Array ^ result = wrapper->_instance->Payload; + info.GetReturnValue().Set(NodeRT::Collections::ArrayWrapper::CreateArrayWrapper( + result, + [](unsigned char val) -> Local + { + return Nan::New(val); + }, + [](Local value) -> bool + { + return value->IsInt32(); + }, + [](Local value) -> unsigned char + { + return static_cast(Nan::To(value).FromMaybe(0)); + })); + return; + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + + static void AddListener(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (info.Length() < 2 || !info[0]->IsString() || !info[1]->IsFunction()) + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString(L"wrong arguments, expected arguments are eventName(string),callback(function)"))); + return; + } + + String::Value eventName(v8::Isolate::GetCurrent(), info[0]); + auto str = *eventName; + + Local callback = info[1].As(); + + ::Windows::Foundation::EventRegistrationToken registrationToken; + if (NodeRT::Utils::CaseInsenstiveEquals(L"canceled", str)) + { + if (!NodeRT::Utils::IsWinRtWrapperOf<::Microsoft::Windows::PushNotifications::PushNotificationReceivedEventArgs ^>(info.This())) + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString(L"The caller of this method isn't of the expected type or internal WinRt object was disposed"))); + return; + } + PushNotificationReceivedEventArgs *wrapper = PushNotificationReceivedEventArgs::Unwrap(info.This()); + + try + { + Persistent *perstPtr = new Persistent(); + perstPtr->Reset(NodeRT::Utils::CreateCallbackObjectInDomain(callback)); + std::shared_ptr> callbackObjPtr(perstPtr, + [](Persistent *ptr) + { + NodeUtils::Async::RunOnMain([ptr]() + { + ptr->Reset(); + delete ptr; }); + }); + + registrationToken = wrapper->_instance->Canceled::add( + ref new ::Windows::ApplicationModel::Background::BackgroundTaskCanceledEventHandler( + [callbackObjPtr](::Windows::ApplicationModel::Background::IBackgroundTaskInstance ^ arg0, ::Windows::ApplicationModel::Background::BackgroundTaskCancellationReason arg1) + { + NodeUtils::Async::RunOnMain([callbackObjPtr, arg0, arg1]() + { + HandleScope scope; + + + Local wrappedArg0; + Local wrappedArg1; + + { + TryCatch tryCatch; + + + wrappedArg0 = NodeRT::Utils::CreateExternalWinRTObject("Windows.ApplicationModel.Background", "IBackgroundTaskInstance", arg0); + wrappedArg1 = Nan::New(static_cast(arg1)); + + + if (wrappedArg0.IsEmpty()) wrappedArg0 = Undefined(); + if (wrappedArg1.IsEmpty()) wrappedArg1 = Undefined(); + } + + Local args[] = { wrappedArg0, wrappedArg1 }; + Local callbackObjLocalRef = Nan::New(*callbackObjPtr); + NodeRT::Utils::CallCallbackInDomain(callbackObjLocalRef, _countof(args), args); }); + })); + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + return; + } + } + else + { + Nan::ThrowError(Nan::Error(String::Concat(v8::Isolate::GetCurrent(), NodeRT::Utils::NewString(L"given event name isn't supported: "), info[0].As()))); + return; + } + + Local tokenMapVal = NodeRT::Utils::GetHiddenValue(callback, Nan::New(REGISTRATION_TOKEN_MAP_PROPERTY_NAME).ToLocalChecked()); + Local tokenMap; + + if (tokenMapVal.IsEmpty() || Nan::Equals(tokenMapVal, Undefined()).FromMaybe(false)) + { + tokenMap = Nan::New(); + NodeRT::Utils::SetHiddenValueWithObject(callback, Nan::New(REGISTRATION_TOKEN_MAP_PROPERTY_NAME).ToLocalChecked(), tokenMap); + } + else + { + tokenMap = Nan::To(tokenMapVal).ToLocalChecked(); + } + + Nan::Set(tokenMap, info[0], CreateOpaqueWrapper(::Windows::Foundation::PropertyValue::CreateInt64(registrationToken.Value))); + } + + static void RemoveListener(Nan::NAN_METHOD_ARGS_TYPE info) + { + HandleScope scope; + + if (info.Length() < 2 || !info[0]->IsString() || !info[1]->IsFunction()) + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString(L"wrong arguments, expected a string and a callback"))); + return; + } + + String::Value eventName(v8::Isolate::GetCurrent(), info[0]); + auto str = *eventName; + + if ((!NodeRT::Utils::CaseInsenstiveEquals(L"canceled", str))) + { + Nan::ThrowError(Nan::Error(String::Concat(v8::Isolate::GetCurrent(), NodeRT::Utils::NewString(L"given event name isn't supported: "), info[0].As()))); + return; + } + + Local callback = info[1].As(); + Local tokenMap = NodeRT::Utils::GetHiddenValue(callback, Nan::New(REGISTRATION_TOKEN_MAP_PROPERTY_NAME).ToLocalChecked()); + + if (tokenMap.IsEmpty() || Nan::Equals(tokenMap, Undefined()).FromMaybe(false)) + { + return; + } + + Local opaqueWrapperObj = Nan::Get(Nan::To(tokenMap).ToLocalChecked(), info[0]).ToLocalChecked(); + + if (opaqueWrapperObj.IsEmpty() || Nan::Equals(opaqueWrapperObj, Undefined()).FromMaybe(false)) + { + return; + } + + OpaqueWrapper *opaqueWrapper = OpaqueWrapper::Unwrap(opaqueWrapperObj.As()); + + long long tokenValue = (long long)opaqueWrapper->GetObjectInstance(); + ::Windows::Foundation::EventRegistrationToken registrationToken; + registrationToken.Value = tokenValue; + + try + { + if (NodeRT::Utils::CaseInsenstiveEquals(L"canceled", str)) + { + if (!NodeRT::Utils::IsWinRtWrapperOf<::Microsoft::Windows::PushNotifications::PushNotificationReceivedEventArgs ^>(info.This())) + { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString(L"The caller of this method isn't of the expected type or internal WinRt object was disposed"))); + return; + } + PushNotificationReceivedEventArgs *wrapper = PushNotificationReceivedEventArgs::Unwrap(info.This()); + wrapper->_instance->Canceled::remove(registrationToken); + } + } + catch (Platform::Exception ^ exception) + { + NodeRT::Utils::ThrowWinRtExceptionInJs(exception); + } + + Nan::Delete(Nan::To(tokenMap).ToLocalChecked(), Nan::To(info[0]).ToLocalChecked()); + } + + private: + ::Microsoft::Windows::PushNotifications::PushNotificationReceivedEventArgs ^ _instance; + static Persistent s_constructorTemplate; + + friend v8::Local WrapPushNotificationReceivedEventArgs(::Microsoft::Windows::PushNotifications::PushNotificationReceivedEventArgs ^ wintRtInstance); + friend ::Microsoft::Windows::PushNotifications::PushNotificationReceivedEventArgs ^ UnwrapPushNotificationReceivedEventArgs(Local value); + }; + + Persistent PushNotificationReceivedEventArgs::s_constructorTemplate; + + v8::Local WrapPushNotificationReceivedEventArgs(::Microsoft::Windows::PushNotifications::PushNotificationReceivedEventArgs ^ winRtInstance) + { + EscapableHandleScope scope; + + if (winRtInstance == nullptr) + { + return scope.Escape(Undefined()); + } + + Local opaqueWrapper = CreateOpaqueWrapper(winRtInstance); + Local args[] = {opaqueWrapper}; + Local localRef = Nan::New(PushNotificationReceivedEventArgs::s_constructorTemplate); + return scope.Escape(Nan::NewInstance(Nan::GetFunction(localRef).ToLocalChecked(), _countof(args), args).ToLocalChecked()); + } + + ::Microsoft::Windows::PushNotifications::PushNotificationReceivedEventArgs ^ UnwrapPushNotificationReceivedEventArgs(Local value) { + return PushNotificationReceivedEventArgs::Unwrap(Nan::To(value).ToLocalChecked())->_instance; + } + + void InitPushNotificationReceivedEventArgs(Local exports) + { + PushNotificationReceivedEventArgs::Init(exports); + } + + } + } + } +} + +NAN_MODULE_INIT(init) +{ + // We ignore failures for now since it probably means that + // the initialization already happened for STA, and that's cool + + CoInitializeEx(nullptr, COINIT_MULTITHREADED); + + /* + if (FAILED(CoInitializeEx(nullptr, COINIT_MULTITHREADED))) { + Nan::ThrowError(Nan::Error(NodeRT::Utils::NewString(L"error in CoInitializeEx()"))); + return; + } + */ + + NodeRT::Microsoft::Windows::PushNotifications::InitPushNotificationChannelStatusEnum(target); + NodeRT::Microsoft::Windows::PushNotifications::InitPushNotificationChannel(target); + NodeRT::Microsoft::Windows::PushNotifications::InitPushNotificationCreateChannelResult(target); + NodeRT::Microsoft::Windows::PushNotifications::InitPushNotificationManager(target); + NodeRT::Microsoft::Windows::PushNotifications::InitPushNotificationReceivedEventArgs(target); + + NodeRT::Utils::RegisterNameSpace("Microsoft.Windows.PushNotifications", target); +} + +NODE_MODULE(binding, init) \ No newline at end of file diff --git a/desktop/addons/windows-pushnotifications/binding.gyp b/desktop/addons/windows-pushnotifications/binding.gyp new file mode 100644 --- /dev/null +++ b/desktop/addons/windows-pushnotifications/binding.gyp @@ -0,0 +1,43 @@ +{ + "variables": { + "USE_ADDITIONAL_WINMD": "true" + }, + "includes": ["common.gypi"], + "targets": [{ + "target_name": "binding", + "sources": [], + "include_dirs": [ + " 0) { + var namespaceRegistry = global.__winRtNamespaces__; + + if (!namespaceRegistry) { + namespaceRegistry = {}; + + Object.defineProperty(global, '__winRtNamespaces__', { + configurable: true, + writable: false, + enumerable: false, + value: namespaceRegistry + }); + } + + function requireNamespace(namespace) { + var moduleName = namespace.toLowerCase(); + + if (npmScope) { + moduleName = '@' + npmScope + '/' + moduleName; + } + + var m = require(moduleName); + delete namespaceRegistry[namespace]; + namespaceRegistry[namespace] = m; + return m; + } + + for (var i in externalReferencedNamespaces) { + var ns = externalReferencedNamespaces[i]; + + if (!namespaceRegistry.hasOwnProperty(ns)) { + Object.defineProperty(namespaceRegistry, ns, { + configurable: true, + enumerable: true, + get: requireNamespace.bind(null, ns) + }); + } + } +} \ No newline at end of file diff --git a/desktop/addons/windows-pushnotifications/node-async.h b/desktop/addons/windows-pushnotifications/node-async.h new file mode 100644 --- /dev/null +++ b/desktop/addons/windows-pushnotifications/node-async.h @@ -0,0 +1,422 @@ +// Copyright (c) The NodeRT Contributors +// All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the ""License""); you may +// not use this file except in compliance with the License. You may obtain a +// copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS +// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY +// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +// MERCHANTABLITY OR NON-INFRINGEMENT. +// +// See the Apache Version 2.0 License for specific language governing +// permissions and limitations under the License. + +#pragma once + +#include +#include "nan.h" + +#include +#include +#include + +#if NAUV_UVVERSION < 0x000b17 +#define NODEASYNC_ASYNC_WORK_CB(func) \ + static void __cdecl func(uv_async_t *handle, int) +#define NODEASYNC_IDLE_WORK_CB(func) \ + static void __cdecl func(uv_idle_t *handle, int) +#else +#define NODEASYNC_ASYNC_WORK_CB(func) \ + static void __cdecl func(uv_async_t *handle) +#define NODEASYNC_IDLE_WORK_CB(func) static void __cdecl func(uv_idle_t *handle) +#endif + +namespace NodeUtils +{ + using Nan::EscapableHandleScope; + using Nan::GetCurrentContext; + using Nan::HandleScope; + using Nan::New; + using Nan::Null; + using Nan::Persistent; + using Nan::Undefined; + using v8::Exception; + using v8::Function; + using v8::Integer; + using v8::Local; + using v8::Object; + using v8::String; + using v8::Value; + + typedef std::function *)> InvokeCallbackDelegate; + + class Async + { + public: + template + struct Baton + { + int error_code; + std::wstring error_message; + + // Custom data + std::shared_ptr data; + std::shared_ptr result; + std::shared_ptr> callback_args; + unsigned callback_args_size; + + Baton() { callback_args_size = 0; } + + void setCallbackArgs(Local *argv, int argc) + { + HandleScope scope; + + callback_info.reset(new Persistent[argc], + [](Persistent *ptr) + { delete[] ptr; }); + + callback_args_size = 0; + + for (int i = 0; i < argc; i++) + { + // callback_info.get()[i] = argv[i]; + callback_info.get()[i].Reset(argv[i]); + } + } + + virtual ~Baton() + { + for (int i = 0; i < callback_args_size; i++) + { + callback_info.get()[i].Reset(); + } + } + + private: + uv_work_t request; + std::function doWork; + std::function afterWork; + Nan::Persistent callbackData; + + friend Async; + }; + + private: + class TokenData + { + public: + static uv_async_t *NewAsyncToken() + { + uv_async_t *asyncHandle = new uv_async_t; + uv_async_init(uv_default_loop(), asyncHandle, AsyncCb); + SetHandleData(asyncHandle->data); + + return asyncHandle; + } + + static uv_async_t *NewAsyncToken(Local callback, + Local receiver) + { + uv_async_t *asyncHandle = NewAsyncToken(); + SetHandleCallbackData(asyncHandle->data, callback, receiver); + + return asyncHandle; + } + + static uv_idle_t *NewIdleToken() + { + uv_idle_t *idleHandle = new uv_idle_t; + uv_idle_init(uv_default_loop(), idleHandle); + + SetHandleData(idleHandle->data); + return idleHandle; + } + + static uv_idle_t *NewIdleToken(Local callback, + Local receiver) + { + uv_idle_t *idleHandle = NewIdleToken(); + SetHandleCallbackData(idleHandle->data, callback, receiver); + + return idleHandle; + } + + virtual ~TokenData() { callbackData.Reset(); } + + private: + static void SetHandleData(void *&handleData) + { + handleData = new TokenData(); + } + + static void SetHandleCallbackData(void *handleData, + Local callback, + Local receiver) + { + TokenData *Token = static_cast(handleData); + Token->callbackData.Reset(CreateCallbackData(callback, receiver)); + } + + TokenData() {} + + Persistent callbackData; + std::function func; + + friend Async; + }; + + public: + template + static void __cdecl Run( + std::shared_ptr input, + std::function *)> doWork, + std::function *)> afterWork, + Local callback, + Local receiver = Local()) + { + HandleScope scope; + Local callbackData = CreateCallbackData(callback, receiver); + + Baton *baton = new Baton(); + baton->request.data = baton; + baton->callbackData.Reset(callbackData); + baton->error_code = 0; + baton->data = input; + baton->doWork = doWork; + baton->afterWork = afterWork; + + uv_queue_work(uv_default_loop(), &baton->request, + AsyncWork, AsyncAfter); + } + + static uv_async_t *__cdecl GetAsyncToken() + { + return TokenData::NewAsyncToken(); + } + + static uv_async_t *__cdecl GetAsyncToken( + Local callback, + Local receiver = Local()) + { + return TokenData::NewAsyncToken(callback, receiver); + } + + static uv_idle_t *__cdecl GetIdleToken() { return TokenData::NewIdleToken(); } + + static uv_idle_t *__cdecl GetIdleToken( + Local callback, + Local receiver = Local()) + { + return TokenData::NewIdleToken(callback, receiver); + } + + static void __cdecl RunOnMain(uv_async_t *async, std::function func) + { + TokenData *Token = static_cast(async->data); + Token->func = func; + uv_async_send(async); + } + + static void __cdecl RunOnMain(std::function func) + { + uv_async_t *async = GetAsyncToken(); + RunOnMain(async, func); + } + + static void __cdecl RunCallbackOnMain( + uv_async_t *async, + std::function func) + { + TokenData *Token = static_cast(async->data); + + InvokeCallbackDelegate invokeCallback = [Token](int argc, + Local *argv) + { + if (!Token->callbackData.IsEmpty()) + { + Nan::AsyncResource asyncResource(Nan::New("RunCallbackOnMain").ToLocalChecked()); + asyncResource.runInAsyncScope(New(Token->callbackData), + New("callback").ToLocalChecked(), argc, argv); + } + }; + + std::function wrapper = [func, invokeCallback]() + { + HandleScope scope; + func(invokeCallback); + }; + + RunOnMain(async, wrapper); + } + + // defers execution of the provided function by creating an idler + // that means, the function will be invoked once the event loop has delivered + // all pending events. + static void __cdecl NextTick(std::function func) + { + uv_idle_t *idler = GetIdleToken(); + NextTick(idler, func); + } + + static void __cdecl NextTick(uv_idle_t *idler, std::function func) + { + TokenData *Token = static_cast(idler->data); + Token->func = func; + + uv_idle_start(idler, onNextTick); + } + + static void __cdecl RunCallbackOnNextTick( + uv_idle_t *idler, + std::function func) + { + TokenData *Token = static_cast(idler->data); + + InvokeCallbackDelegate invokeCallback = [Token](int argc, + Local *argv) + { + if (!Token->callbackData.IsEmpty()) + { + Nan::AsyncResource asyncResource(Nan::New("RunCallbackOnNextTick").ToLocalChecked()); + asyncResource.runInAsyncScope(New(Token->callbackData), + New("callback").ToLocalChecked(), argc, argv); + } + }; + + std::function wrapper = [func, invokeCallback]() + { + HandleScope scope; + func(invokeCallback); + }; + + NextTick(idler, wrapper); + } + + private: + static Local CreateCallbackData(Local callback, + Local receiver) + { + EscapableHandleScope scope; + + Local callbackData; + if (!callback.IsEmpty() && !callback->Equals(Nan::GetCurrentContext(), Undefined()).FromMaybe(true)) + { + callbackData = New(); + + if (!receiver.IsEmpty()) + { + Nan::SetPrototype(callbackData, receiver); + } + + Nan::Set(callbackData, New("callback").ToLocalChecked(), + callback); + + // get the current domain: + Local currentDomain = Undefined(); + + Local process = + Nan::To(Nan::Get(GetCurrentContext()->Global(), + New("process").ToLocalChecked()) + .ToLocalChecked()) + .ToLocalChecked(); + if (!process->Equals(Nan::GetCurrentContext(), Undefined()).FromMaybe(true)) + { + currentDomain = process->Get(Nan::GetCurrentContext(), New("domain").ToLocalChecked()).ToLocalChecked(); + } + + Nan::Set(callbackData, New("domain").ToLocalChecked(), + currentDomain); + } + + return scope.Escape(callbackData); + }; + + template + static void __cdecl AsyncWork(uv_work_t *req) + { + // No HandleScope! + + Baton *baton = + static_cast *>(req->data); + + // Do work in threadpool here. + // Set baton->error_code/message on failures. + // Set baton->result with a final result object + baton->doWork(baton); + } + + template + static void __cdecl AsyncAfter(uv_work_t *req, int status) + { + HandleScope scope; + ; + Baton *baton = + static_cast *>(req->data); + + // typical AfterWorkFunc implementation + // if (baton->error) + //{ + // Local err = Exception::Error(...); + // Local argv[] = { err }; + // baton->setCallbackArgs(argv, _countof(argv)); + //} + // else + //{ + // Local argv[] = { Undefined(), ... }; + // baton->setCallbackArgs(argv, _countof(argv)); + //} + + baton->afterWork(baton); + + if (!baton->callbackData.IsEmpty()) + { + // call the callback, using domains and all + int argc = static_cast(baton->callback_args_size); + std::unique_ptr> handlesArr(new Local[argc]); + for (int i = 0; i < argc; i++) + { + handlesArr.get()[i] = New(baton->callback_info.get()[i]); + } + + Nan::AsyncResource asyncResource(Nan::New("AsyncAfter").ToLocalChecked()); + asyncResource.callInAsyncScope(New(baton->callbackData), + New("callback").ToLocalChecked(), argc, + handlesArr.get()); + } + + baton->callbackData.Reset(); + delete baton; + } + + // called after the async handle is closed in order to free it's memory + static void __cdecl AyncCloseCb(uv_handle_t *handle) + { + if (handle != nullptr) + { + uv_async_t *async = reinterpret_cast(handle); + delete async; + } + } + + // Called by run on main in case we are not running on the main thread + NODEASYNC_ASYNC_WORK_CB(AsyncCb) + { + auto Token = static_cast(handle->data); + Token->func(); + uv_close((uv_handle_t *)handle, AyncCloseCb); + delete Token; + } + + NODEASYNC_IDLE_WORK_CB(onNextTick) + { + std::function *func = + static_cast *>(handle->data); + (*func)(); + delete func; + uv_idle_stop(handle); + delete handle; + } + }; +} // namespace NodeUtils diff --git a/desktop/addons/windows-pushnotifications/package.json b/desktop/addons/windows-pushnotifications/package.json new file mode 100644 --- /dev/null +++ b/desktop/addons/windows-pushnotifications/package.json @@ -0,0 +1,40 @@ +{ + "name": "microsoft.windows.pushnotifications", + "version": "0.0.1", + "description": "Use the Microsoft.Windows.PushNotifications UWP API directly from Node.js", + "main": "lib/main.js", + "keywords": [ + "Microsoft.Windows.PushNotifications", + "Microsoft", + "Windows", + "PushNotifications", + "PushNotificationChannel", + "PushNotificationCreateChannelResult", + "PushNotificationManager", + "PushNotificationReceivedEventArgs", + "PushNotificationChannelStatus", + "PushNotificationCreateChannelStatus", + "PushNotificationsContract", + "NodeRT", + "WinRT", + "Microsoft" + ], + "dependencies": { + "nan": "2.17.0" + }, + "devDependencies": { + "node-gyp": "^9.3.1" + }, + "repository": { + "type": "git", + "url": "git://github.com/NodeRT/NodeRT.git" + }, + "homepage": "https://github.com/NodeRT/NodeRT", + "author": "Generated by NodeRT", + "contributors": [ + "nadavbar (http://www.nadavos.com)", + "Felix Rieseberg (https://www.felix.fun)" + ], + "gypfile": true, + "license": "Apache-2.0" +} diff --git a/desktop/forge.config.cjs b/desktop/forge.config.cjs --- a/desktop/forge.config.cjs +++ b/desktop/forge.config.cjs @@ -124,6 +124,7 @@ '\\.eslintrc\\.json', '\\.flowconfig', 'flow-typed', + 'addons', ], appBundleId: 'app.comm.macos', ...signingOptions.packagerMacos,