@react-native-windows/automation-channel 0.0.0-canary.1016

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,56 @@
1
+ # @react-native-windows/automation-channel
2
+
3
+ @react-native-windows/automation-channel adds support for remote procedure calls from a node client to react-native-windows server on the same machine.
4
+
5
+ ## Example
6
+
7
+ _node app_
8
+ ```ts
9
+ import {waitForConnection} from '@react-native-windows/automation-channel'
10
+
11
+ const rpcConnection = await waitForConnection({port: 8305});
12
+ const result = await rpcConnection.invoke("add", [2, 2])
13
+ ```
14
+
15
+ _react-native-windows app_
16
+ ```c++
17
+ #include "winrt/AutomationChannel.Server.h"
18
+
19
+ // AutomationChannel::CommandHandler allows registering methods
20
+ winrt::AutomationChannel::CommandHandler handler();
21
+
22
+ // Binding to a simple method
23
+ handler.BindOperation("add", [](const JSonValue& params) noexcept {
24
+ auto addends = params.GetArray();
25
+
26
+ auto sum = 0;
27
+ for (const auto& addend : addends) {
28
+ sum += addend.GetNumber();
29
+ }
30
+
31
+ return JSonValue::CreateNumberValue(sum);
32
+ });
33
+
34
+ // Methods may be bound to IAsyncAction or IAsyncOperation
35
+ handler.BindAsyncAction("performAsyncOperation", [](const JSonValue& params) noexcept -> IAsyncAction {
36
+ co_await performLongOperation();
37
+ });
38
+
39
+ // Start server
40
+ winrt::AutomationChannel::Server rpcServer(handler);
41
+ co_await rpcServer.ProcessAllClientRequests(8305, 50ms);
42
+ ```
43
+
44
+ ## Installing
45
+ @react-native-windows/automation-channel supports [auto-linking](https://microsoft.github.io/react-native-windows/docs/native-modules-autolinking) to allow installation into react-native-windows applications.
46
+
47
+
48
+ ## Architecture
49
+ **Reverse TCP server:** Traditional server/client roles are reversed, where the node client creates a TCP server to connect to. This helps to bypass restrictions on inbound loopback traffic to UWP apps. This low-effort solution allows bypassing the UWP AppContainer.
50
+
51
+ ### Alternative approaches
52
+ - **Named pipe created inside AppContainer:** Node provides first-class support for named-pipes through `net.socket`. It is possible to create a named pipe from a UWP process which a Win32 process can then connect to, allowing traditional server/client roles. Doing this requires locating the resource local to the AppContainer, using an API like `GetAppContainerNamedObjectPath`. This likely requires FFI (with node-gyp) or native extenssions.
53
+ - **Proxy to full-trust process** The RNW application could create a full-trust process which proxies from TCP to named-pipe internal to the AppContainer. This bypasses inbound loopback restrictions, but adds complexity of deploying a separate process, requires two IPC channels.
54
+
55
+ ### Protocol
56
+ @react-native-windows/automation-channel uses a TCP channel, sending JSON messages across the wire prefixed with length. Messages themselves are conformant to the [JSON-RPC](https://en.wikipedia.org/wiki/JSON-RPC) version 2.0 protocol.
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Copyright (c) Microsoft Corporation.
3
+ * Licensed under the MIT License.
4
+ *
5
+ * @format
6
+ */
7
+ /// <reference types="node" />
8
+ import { Server, Socket } from 'net';
9
+ export type InvokeResult = {
10
+ type: 'error';
11
+ code: any;
12
+ message: string;
13
+ } | {
14
+ type: 'success';
15
+ result?: any;
16
+ };
17
+ export declare class AutomationClient {
18
+ private readonly socket;
19
+ private readonly server;
20
+ private readonly pendingRequests;
21
+ private receiveBuffer;
22
+ constructor(socket: Socket, server: Server);
23
+ invoke(methodName: string, params: any[] | Record<string, any>): Promise<InvokeResult>;
24
+ close(): void;
25
+ private onData;
26
+ private onEnd;
27
+ private onError;
28
+ private onMessage;
29
+ }
30
+ export declare function waitForConnection(opts: {
31
+ port: number;
32
+ }): Promise<AutomationClient>;
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) Microsoft Corporation.
4
+ * Licensed under the MIT License.
5
+ *
6
+ * @format
7
+ */
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.waitForConnection = exports.AutomationClient = void 0;
13
+ const net_1 = require("net");
14
+ const jsonrpc_lite_1 = __importDefault(require("jsonrpc-lite"));
15
+ let incrementingId = 0;
16
+ class AutomationClient {
17
+ constructor(socket, server) {
18
+ this.socket = socket;
19
+ this.server = server;
20
+ this.pendingRequests = new Map();
21
+ this.receiveBuffer = Buffer.alloc(0);
22
+ this.socket.on('data', this.onData.bind(this));
23
+ this.socket.on('end', this.onEnd.bind(this));
24
+ this.socket.on('error', this.onError.bind(this));
25
+ }
26
+ invoke(methodName, params) {
27
+ return new Promise((resolve, reject) => {
28
+ const messageId = ++incrementingId;
29
+ this.pendingRequests.set(messageId, (result, err) => {
30
+ if (err) {
31
+ reject(err);
32
+ }
33
+ if (result) {
34
+ resolve(result);
35
+ }
36
+ });
37
+ const requestString = jsonrpc_lite_1.default
38
+ .request(messageId, methodName, params)
39
+ .serialize();
40
+ const requestBuffer = Buffer.from(requestString, 'utf-8');
41
+ const sizeBuffer = Buffer.alloc(4);
42
+ sizeBuffer.writeUInt32LE(requestBuffer.length);
43
+ this.socket.write(sizeBuffer);
44
+ this.socket.write(requestBuffer);
45
+ });
46
+ }
47
+ close() {
48
+ this.socket.destroy();
49
+ this.server.close();
50
+ }
51
+ onData(chunk) {
52
+ this.receiveBuffer = Buffer.concat([this.receiveBuffer, chunk]);
53
+ if (this.receiveBuffer.length >= 4) {
54
+ const messageLength = this.receiveBuffer.readUInt32LE();
55
+ const totalLength = messageLength + 4;
56
+ if (this.receiveBuffer.length >= totalLength) {
57
+ const messageBuffer = this.receiveBuffer.slice(4, totalLength);
58
+ if (totalLength < this.receiveBuffer.length) {
59
+ this.receiveBuffer = Buffer.from(this.receiveBuffer, totalLength);
60
+ }
61
+ else {
62
+ this.receiveBuffer = Buffer.alloc(0);
63
+ }
64
+ this.onMessage(messageBuffer);
65
+ }
66
+ }
67
+ }
68
+ onEnd() {
69
+ this.pendingRequests.forEach(req => req(null, new Error('Unexpected disconnect from RPC server')));
70
+ }
71
+ onError(error) {
72
+ this.pendingRequests.forEach(req => req(null, error));
73
+ }
74
+ onMessage(message) {
75
+ const response = jsonrpc_lite_1.default.parseJsonRpcString(message.toString('utf8'));
76
+ if (Array.isArray(response)) {
77
+ throw new Error('Expected single message');
78
+ }
79
+ switch (response.type) {
80
+ case "request" /* RpcStatusType.request */:
81
+ throw new Error('Received JSON-RPC request instead of response');
82
+ case "notification" /* RpcStatusType.notification */:
83
+ throw new Error('Unexpected JSON-RPC notification');
84
+ case "invalid" /* RpcStatusType.invalid */:
85
+ throw new Error('Invalid JSON-RPC2 response: ' +
86
+ JSON.stringify(response.payload, null, 2));
87
+ case "success" /* RpcStatusType.success */: {
88
+ const pendingReq = this.pendingRequests.get(response.payload.id);
89
+ if (!pendingReq) {
90
+ throw new Error('Could not find pending request from response ID');
91
+ }
92
+ this.pendingRequests.delete(response.payload.id);
93
+ pendingReq({ type: 'success', result: response.payload.result }, null);
94
+ break;
95
+ }
96
+ case "error" /* RpcStatusType.error */: {
97
+ const pendingReq = this.pendingRequests.get(response.payload.id);
98
+ if (!pendingReq) {
99
+ throw new Error('Could not find pending request from response ID');
100
+ }
101
+ this.pendingRequests.delete(response.payload.id);
102
+ pendingReq({ type: 'error', ...response.payload.error }, null);
103
+ break;
104
+ }
105
+ }
106
+ }
107
+ }
108
+ exports.AutomationClient = AutomationClient;
109
+ function waitForConnection(opts) {
110
+ return new Promise((resolve, reject) => {
111
+ const server = new net_1.Server();
112
+ server.listen(opts.port);
113
+ const onError = (err) => reject(err);
114
+ server.on('error', onError);
115
+ server.on('connection', socket => {
116
+ server.off('error', onError);
117
+ resolve(new AutomationClient(socket, server));
118
+ });
119
+ });
120
+ }
121
+ exports.waitForConnection = waitForConnection;
122
+ //# sourceMappingURL=automationChannel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"automationChannel.js","sourceRoot":"","sources":["../src/automationChannel.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Copyright (c) Microsoft Corporation.\n * Licensed under the MIT License.\n *\n * @format\n */\n\nimport {Server, Socket} from 'net';\nimport jsonrpc from 'jsonrpc-lite';\nimport {RpcStatusType} from 'jsonrpc-lite';\n\nlet incrementingId = 0;\n\nexport type InvokeResult =\n | {type: 'error'; code: any; message: string}\n | {type: 'success'; result?: any};\n\nexport class AutomationClient {\n private readonly socket: Socket;\n private readonly server: Server;\n private readonly pendingRequests: Map<\n any,\n (result: InvokeResult | null, err: Error | null) => void\n >;\n private receiveBuffer: Buffer;\n\n constructor(socket: Socket, server: Server) {\n this.socket = socket;\n this.server = server;\n\n this.pendingRequests = new Map();\n this.receiveBuffer = Buffer.alloc(0);\n\n this.socket.on('data', this.onData.bind(this));\n this.socket.on('end', this.onEnd.bind(this));\n this.socket.on('error', this.onError.bind(this));\n }\n\n invoke(\n methodName: string,\n params: any[] | Record<string, any>,\n ): Promise<InvokeResult> {\n return new Promise((resolve, reject) => {\n const messageId = ++incrementingId;\n this.pendingRequests.set(messageId, (result, err) => {\n if (err) {\n reject(err);\n }\n if (result) {\n resolve(result);\n }\n });\n\n const requestString = jsonrpc\n .request(messageId, methodName, params)\n .serialize();\n\n const requestBuffer = Buffer.from(requestString, 'utf-8');\n const sizeBuffer = Buffer.alloc(4);\n sizeBuffer.writeUInt32LE(requestBuffer.length);\n\n this.socket.write(sizeBuffer);\n this.socket.write(requestBuffer);\n });\n }\n\n close() {\n this.socket.destroy();\n this.server.close();\n }\n\n private onData(chunk: Buffer) {\n this.receiveBuffer = Buffer.concat([this.receiveBuffer, chunk]);\n if (this.receiveBuffer.length >= 4) {\n const messageLength = this.receiveBuffer.readUInt32LE();\n const totalLength = messageLength + 4;\n\n if (this.receiveBuffer.length >= totalLength) {\n const messageBuffer = this.receiveBuffer.slice(4, totalLength);\n\n if (totalLength < this.receiveBuffer.length) {\n this.receiveBuffer = Buffer.from(this.receiveBuffer, totalLength);\n } else {\n this.receiveBuffer = Buffer.alloc(0);\n }\n\n this.onMessage(messageBuffer);\n }\n }\n }\n\n private onEnd() {\n this.pendingRequests.forEach(req =>\n req(null, new Error('Unexpected disconnect from RPC server')),\n );\n }\n\n private onError(error: Error) {\n this.pendingRequests.forEach(req => req(null, error));\n }\n\n private onMessage(message: Buffer) {\n const response = jsonrpc.parseJsonRpcString(message.toString('utf8'));\n if (Array.isArray(response)) {\n throw new Error('Expected single message');\n }\n\n switch (response.type) {\n case RpcStatusType.request:\n throw new Error('Received JSON-RPC request instead of response');\n case RpcStatusType.notification:\n throw new Error('Unexpected JSON-RPC notification');\n case RpcStatusType.invalid:\n throw new Error(\n 'Invalid JSON-RPC2 response: ' +\n JSON.stringify(response.payload, null, 2),\n );\n\n case RpcStatusType.success: {\n const pendingReq = this.pendingRequests.get(response.payload.id);\n if (!pendingReq) {\n throw new Error('Could not find pending request from response ID');\n }\n\n this.pendingRequests.delete(response.payload.id);\n pendingReq({type: 'success', result: response.payload.result}, null);\n break;\n }\n\n case RpcStatusType.error: {\n const pendingReq = this.pendingRequests.get(response.payload.id);\n if (!pendingReq) {\n throw new Error('Could not find pending request from response ID');\n }\n\n this.pendingRequests.delete(response.payload.id);\n pendingReq({type: 'error', ...response.payload.error}, null);\n break;\n }\n }\n }\n}\n\nexport function waitForConnection(opts: {\n port: number;\n}): Promise<AutomationClient> {\n return new Promise((resolve, reject) => {\n const server = new Server();\n server.listen(opts.port);\n\n const onError = (err: Error) => reject(err);\n server.on('error', onError);\n server.on('connection', socket => {\n server.off('error', onError);\n resolve(new AutomationClient(socket, server));\n });\n });\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@react-native-windows/automation-channel",
3
+ "version": "0.0.0-canary.1016",
4
+ "license": "MIT",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/microsoft/react-native-windows",
8
+ "directory": "packages/@react-native-windows/automation-channel"
9
+ },
10
+ "scripts": {
11
+ "build": "rnw-scripts build",
12
+ "clean": "rnw-scripts clean",
13
+ "lint": "rnw-scripts lint",
14
+ "lint:fix": "rnw-scripts lint:fix",
15
+ "watch": "rnw-scripts watch",
16
+ "windows": "npx @react-native-community/cli run-windows"
17
+ },
18
+ "main": "lib-commonjs/automationChannel.js",
19
+ "dependencies": {
20
+ "@typescript-eslint/eslint-plugin": "^7.1.1",
21
+ "@typescript-eslint/parser": "^7.1.1",
22
+ "jsonrpc-lite": "^2.2.0"
23
+ },
24
+ "devDependencies": {
25
+ "@react-native-community/cli": "20.0.0",
26
+ "@rnw-scripts/eslint-config": "1.2.38",
27
+ "@rnw-scripts/just-task": "2.3.58",
28
+ "@rnw-scripts/ts-config": "2.0.6",
29
+ "@types/find-up": "^4.0.0",
30
+ "@types/node": "^22.14.0",
31
+ "eslint": "^8.19.0",
32
+ "just-scripts": "^1.3.2",
33
+ "prettier": "2.8.8",
34
+ "react": "19.1.0",
35
+ "react-native": "0.82.0-nightly-20250806-5936f29d6",
36
+ "react-native-windows": "^0.0.0-canary.1016",
37
+ "typescript": "5.0.4"
38
+ },
39
+ "files": [
40
+ "lib-commonjs",
41
+ "windows",
42
+ "!packages*.lock.json"
43
+ ],
44
+ "beachball": {
45
+ "defaultNpmTag": "canary",
46
+ "disallowedChangeTypes": [
47
+ "major",
48
+ "minor",
49
+ "patch",
50
+ "premajor",
51
+ "preminor",
52
+ "prepatch"
53
+ ]
54
+ },
55
+ "promoteRelease": true,
56
+ "engines": {
57
+ "node": ">= 22"
58
+ }
59
+ }
@@ -0,0 +1,3 @@
1
+ EXPORTS
2
+ DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE
3
+ DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE
@@ -0,0 +1,22 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3
+ <ItemGroup>
4
+ <ClCompile Include="pch.cpp" />
5
+ <ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
6
+ <ClCompile Include="JsonRpcRequestProcessor.cpp" />
7
+ </ItemGroup>
8
+ <ItemGroup>
9
+ <ClInclude Include="pch.h" />
10
+ <ClInclude Include="JsonRpcRequestProcessor.h" />
11
+ <ClInclude Include="CppWinrtLessExceptions.h" />
12
+ </ItemGroup>
13
+ <ItemGroup>
14
+ <None Include="PropertySheet.props" />
15
+ <None Include="AutomationChannel.def" />
16
+ </ItemGroup>
17
+ <ItemGroup>
18
+ <Midl Include="Server.idl" />
19
+ <Midl Include="CommandHandler.idl" />
20
+ <Midl Include="ReactPackageProvider.idl" />
21
+ </ItemGroup>
22
+ </Project>
@@ -0,0 +1,154 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <Project ToolsVersion="Current" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3
+ <Import Project="$(SolutionDir)\ExperimentalFeatures.props" Condition="Exists('$(SolutionDir)\ExperimentalFeatures.props')" />
4
+ <PropertyGroup Label="Globals">
5
+ <CppWinRTOptimized>true</CppWinRTOptimized>
6
+ <CppWinRTRootNamespaceAutoMerge>true</CppWinRTRootNamespaceAutoMerge>
7
+ <MinimalCoreWin>true</MinimalCoreWin>
8
+ <ProjectGuid>{c0a69310-6119-46dc-a6d6-0bab7826dc92}</ProjectGuid>
9
+ <ProjectName>AutomationChannel</ProjectName>
10
+ <RootNamespace>AutomationChannel</RootNamespace>
11
+ <DefaultLanguage>en-US</DefaultLanguage>
12
+ <MinimumVisualStudioVersion>17.0</MinimumVisualStudioVersion>
13
+ <AppContainerApplication>true</AppContainerApplication>
14
+ <ApplicationType>Windows Store</ApplicationType>
15
+ <ApplicationTypeRevision>10.0</ApplicationTypeRevision>
16
+ </PropertyGroup>
17
+ <PropertyGroup Label="ReactNativeWindowsProps">
18
+ <ReactNativeWindowsDir Condition="'$(ReactNativeWindowsDir)' == ''">$([MSBuild]::GetDirectoryNameOfFileAbove($(SolutionDir), 'node_modules\react-native-windows\package.json'))\node_modules\react-native-windows\</ReactNativeWindowsDir>
19
+ </PropertyGroup>
20
+ <Import Project="$(ReactNativeWindowsDir)\PropertySheets\External\Microsoft.ReactNative.WindowsSdk.Default.props" />
21
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
22
+ <ItemGroup Label="ProjectConfigurations">
23
+ <ProjectConfiguration Include="Debug|ARM64">
24
+ <Configuration>Debug</Configuration>
25
+ <Platform>ARM64</Platform>
26
+ </ProjectConfiguration>
27
+ <ProjectConfiguration Include="Debug|Win32">
28
+ <Configuration>Debug</Configuration>
29
+ <Platform>Win32</Platform>
30
+ </ProjectConfiguration>
31
+ <ProjectConfiguration Include="Debug|x64">
32
+ <Configuration>Debug</Configuration>
33
+ <Platform>x64</Platform>
34
+ </ProjectConfiguration>
35
+ <ProjectConfiguration Include="Release|ARM64">
36
+ <Configuration>Release</Configuration>
37
+ <Platform>ARM64</Platform>
38
+ </ProjectConfiguration>
39
+ <ProjectConfiguration Include="Release|Win32">
40
+ <Configuration>Release</Configuration>
41
+ <Platform>Win32</Platform>
42
+ </ProjectConfiguration>
43
+ <ProjectConfiguration Include="Release|x64">
44
+ <Configuration>Release</Configuration>
45
+ <Platform>x64</Platform>
46
+ </ProjectConfiguration>
47
+ </ItemGroup>
48
+ <PropertyGroup Label="Configuration">
49
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
50
+ <CharacterSet>Unicode</CharacterSet>
51
+ <GenerateManifest>false</GenerateManifest>
52
+ </PropertyGroup>
53
+ <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
54
+ <UseDebugLibraries>true</UseDebugLibraries>
55
+ <LinkIncremental>true</LinkIncremental>
56
+ </PropertyGroup>
57
+ <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
58
+ <UseDebugLibraries>false</UseDebugLibraries>
59
+ <WholeProgramOptimization>true</WholeProgramOptimization>
60
+ <LinkIncremental>false</LinkIncremental>
61
+ </PropertyGroup>
62
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
63
+ <ImportGroup Label="ExtensionSettings">
64
+ </ImportGroup>
65
+ <ImportGroup Label="PropertySheets">
66
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
67
+ </ImportGroup>
68
+ <ImportGroup Label="PropertySheets">
69
+ <Import Project="PropertySheet.props" />
70
+ </ImportGroup>
71
+ <ImportGroup Label="ReactNativeWindowsPropertySheets">
72
+ <Import Project="$(ReactNativeWindowsDir)\PropertySheets\external\Microsoft.ReactNative.CppLib.props" Condition="Exists('$(ReactNativeWindowsDir)\PropertySheets\External\Microsoft.ReactNative.CppLib.props')" />
73
+ <!-- Added since we build this project with Paper/Fabric. -->
74
+ <Import Project="$(ReactNativeWindowsDir)\PropertySheets\NuGet.LockFile.props" />
75
+ </ImportGroup>
76
+ <PropertyGroup Label="UserMacros" />
77
+ <ItemDefinitionGroup>
78
+ <ClCompile>
79
+ <PrecompiledHeader>Use</PrecompiledHeader>
80
+ <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
81
+ <PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
82
+ <WarningLevel>Level4</WarningLevel>
83
+ <AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions>
84
+ <DisableSpecificWarnings>4453;28204</DisableSpecificWarnings>
85
+ <PreprocessorDefinitions>_WINRT_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
86
+ <AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
87
+ </ClCompile>
88
+ <Link>
89
+ <SubSystem>Console</SubSystem>
90
+ <GenerateWindowsMetadata>true</GenerateWindowsMetadata>
91
+ <ModuleDefinitionFile>AutomationChannel.def</ModuleDefinitionFile>
92
+ </Link>
93
+ </ItemDefinitionGroup>
94
+ <ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
95
+ <ClCompile>
96
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
97
+ </ClCompile>
98
+ </ItemDefinitionGroup>
99
+ <ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
100
+ <ClCompile>
101
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
102
+ </ClCompile>
103
+ </ItemDefinitionGroup>
104
+ <ItemGroup>
105
+ <ClInclude Include="CppWinrtLessExceptions.h" />
106
+ <ClInclude Include="JsonRpcRequestProcessor.h" />
107
+ <ClInclude Include="Server.h">
108
+ <DependentUpon>Server.idl</DependentUpon>
109
+ </ClInclude>
110
+ <ClInclude Include="CommandHandler.h">
111
+ <DependentUpon>CommandHandler.idl</DependentUpon>
112
+ </ClInclude>
113
+ <ClInclude Include="ReactPackageProvider.h">
114
+ <DependentUpon>ReactPackageProvider.idl</DependentUpon>
115
+ </ClInclude>
116
+ <ClInclude Include="pch.h" />
117
+ </ItemGroup>
118
+ <ItemGroup>
119
+ <ClCompile Include="JsonRpcRequestProcessor.cpp" />
120
+ <ClCompile Include="pch.cpp">
121
+ <PrecompiledHeader>Create</PrecompiledHeader>
122
+ </ClCompile>
123
+ <ClCompile Include="Server.cpp">
124
+ <DependentUpon>Server.idl</DependentUpon>
125
+ </ClCompile>
126
+ <ClCompile Include="CommandHandler.cpp">
127
+ <DependentUpon>CommandHandler.idl</DependentUpon>
128
+ </ClCompile>
129
+ <ClCompile Include="ReactPackageProvider.cpp">
130
+ <DependentUpon>ReactPackageProvider.idl</DependentUpon>
131
+ </ClCompile>
132
+ <ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
133
+ </ItemGroup>
134
+ <ItemGroup>
135
+ <Midl Include="CommandHandler.idl" />
136
+ <Midl Include="ReactPackageProvider.idl" />
137
+ <Midl Include="Server.idl" />
138
+ </ItemGroup>
139
+ <ItemGroup>
140
+ <None Include="AutomationChannel.def" />
141
+ <None Include="PropertySheet.props" />
142
+ </ItemGroup>
143
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
144
+ <ImportGroup Label="ReactNativeWindowsTargets">
145
+ <Import Project="$(ReactNativeWindowsDir)\PropertySheets\External\Microsoft.ReactNative.CppLib.targets" Condition="Exists('$(ReactNativeWindowsDir)\PropertySheets\External\Microsoft.ReactNative.CppLib.targets')" />
146
+ </ImportGroup>
147
+ <Target Name="EnsureReactNativeWindowsTargets" BeforeTargets="PrepareForBuild">
148
+ <PropertyGroup>
149
+ <ErrorText>This project references targets in your node_modules\react-native-windows folder that are missing. The missing file is {0}.</ErrorText>
150
+ </PropertyGroup>
151
+ <Error Condition="!Exists('$(ReactNativeWindowsDir)\PropertySheets\External\Microsoft.ReactNative.CppLib.props')" Text="$([System.String]::Format('$(ErrorText)', '$(ReactNativeWindowsDir)\PropertySheets\External\Microsoft.ReactNative.CppLib.props'))" />
152
+ <Error Condition="!Exists('$(ReactNativeWindowsDir)\PropertySheets\External\Microsoft.ReactNative.CppLib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(ReactNativeWindowsDir)\PropertySheets\External\Microsoft.ReactNative.CppLib.targets'))" />
153
+ </Target>
154
+ </Project>
@@ -0,0 +1,91 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+
4
+ #include "pch.h"
5
+ #include "CommandHandler.h"
6
+ #include "CommandHandler.g.cpp"
7
+
8
+ #include <Crash.h>
9
+
10
+ using namespace winrt::Windows::Foundation;
11
+ using namespace winrt::Windows::Data::Json;
12
+
13
+ namespace winrt::AutomationChannel::implementation {
14
+ winrt::AutomationChannel::CommandHandler CommandHandler::BindAction(
15
+ const winrt::hstring &methodName,
16
+ const SyncAction &action) noexcept {
17
+ VerifyElseCrash(!IsMethodRegistered(methodName));
18
+ VerifyElseCrash(!IsReservedMethodName(methodName));
19
+
20
+ m_actionHandlers[methodName] = action;
21
+ return AutomationChannel::CommandHandler(*this);
22
+ }
23
+
24
+ winrt::AutomationChannel::CommandHandler CommandHandler::BindAsyncAction(
25
+ const winrt::hstring &methodName,
26
+ const AsyncAction &action) noexcept {
27
+ VerifyElseCrash(!IsMethodRegistered(methodName));
28
+ VerifyElseCrash(!IsReservedMethodName(methodName));
29
+
30
+ m_asyncActionHandlers[methodName] = action;
31
+ return AutomationChannel::CommandHandler(*this);
32
+ }
33
+
34
+ winrt::AutomationChannel::CommandHandler CommandHandler::BindOperation(
35
+ const winrt::hstring &methodName,
36
+ const SyncOperation &operation) noexcept {
37
+ VerifyElseCrash(!IsMethodRegistered(methodName));
38
+ VerifyElseCrash(!IsReservedMethodName(methodName));
39
+
40
+ m_operationHandlers[methodName] = operation;
41
+ return AutomationChannel::CommandHandler(*this);
42
+ }
43
+
44
+ winrt::AutomationChannel::CommandHandler CommandHandler::BindAsyncOperation(
45
+ const winrt::hstring &methodName,
46
+ const AsyncOperation &operation) noexcept {
47
+ VerifyElseCrash(!IsMethodRegistered(methodName));
48
+ VerifyElseCrash(!IsReservedMethodName(methodName));
49
+
50
+ m_asyncOperationHandlers[methodName] = operation;
51
+ return AutomationChannel::CommandHandler(*this);
52
+ }
53
+
54
+ bool CommandHandler::IsMethodRegistered(const winrt::hstring &methodName) noexcept {
55
+ return m_actionHandlers.count(methodName) != 0 || m_operationHandlers.count(methodName) != 0 ||
56
+ m_asyncActionHandlers.count(methodName) != 0 || m_asyncOperationHandlers.count(methodName) != 0;
57
+ }
58
+
59
+ bool CommandHandler::IsReservedMethodName(const winrt::hstring &methodName) noexcept {
60
+ constexpr std::wstring_view reservedPrefix = L"rpc.";
61
+
62
+ return std::wstring_view(methodName).compare(0, reservedPrefix.size(), reservedPrefix, 0, reservedPrefix.size()) == 0;
63
+ }
64
+
65
+ IAsyncOperation<IJsonValue> CommandHandler::Invoke(const winrt::hstring &methodName, const JsonValue &params) {
66
+ auto action = m_actionHandlers.find(methodName);
67
+ if (action != m_actionHandlers.end()) {
68
+ action->second(params);
69
+ co_return JsonValue::CreateNullValue();
70
+ }
71
+
72
+ auto operation = m_operationHandlers.find(methodName);
73
+ if (operation != m_operationHandlers.end()) {
74
+ auto result = operation->second(params);
75
+ co_return result;
76
+ }
77
+
78
+ auto asyncAction = m_asyncActionHandlers.find(methodName);
79
+ if (asyncAction != m_asyncActionHandlers.end()) {
80
+ co_await asyncAction->second(params);
81
+ co_return JsonValue::CreateNullValue();
82
+ }
83
+
84
+ auto asyncOperation = m_asyncOperationHandlers.find(methodName);
85
+ if (asyncOperation != m_asyncOperationHandlers.end()) {
86
+ auto result = co_await asyncOperation->second(params);
87
+ co_return result;
88
+ }
89
+ }
90
+
91
+ } // namespace winrt::AutomationChannel::implementation
@@ -0,0 +1,42 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+
4
+ #pragma once
5
+ #include "CommandHandler.g.h"
6
+
7
+ namespace winrt::AutomationChannel::implementation {
8
+
9
+ struct CommandHandler : CommandHandlerT<CommandHandler> {
10
+ CommandHandler() = default;
11
+
12
+ AutomationChannel::CommandHandler BindAction(const winrt::hstring &methodName, const SyncAction &action) noexcept;
13
+ AutomationChannel::CommandHandler BindAsyncAction(
14
+ const winrt::hstring &methodName,
15
+ const AsyncAction &action) noexcept;
16
+ AutomationChannel::CommandHandler BindOperation(
17
+ const winrt::hstring &methodName,
18
+ const SyncOperation &operation) noexcept;
19
+ AutomationChannel::CommandHandler BindAsyncOperation(
20
+ const winrt::hstring &methodName,
21
+ const AsyncOperation &operation) noexcept;
22
+
23
+ bool IsMethodRegistered(const winrt::hstring &methodName) noexcept;
24
+ bool IsReservedMethodName(const winrt::hstring &methodName) noexcept;
25
+ Windows::Foundation::IAsyncOperation<Windows::Data::Json::IJsonValue> Invoke(
26
+ const winrt::hstring &methodName,
27
+ const Windows::Data::Json::JsonValue &params);
28
+
29
+ private:
30
+ std::unordered_map<winrt::hstring, SyncAction> m_actionHandlers;
31
+ std::unordered_map<winrt::hstring, SyncOperation> m_operationHandlers;
32
+ std::unordered_map<winrt::hstring, AsyncAction> m_asyncActionHandlers;
33
+ std::unordered_map<winrt::hstring, AsyncOperation> m_asyncOperationHandlers;
34
+ };
35
+
36
+ } // namespace winrt::AutomationChannel::implementation
37
+
38
+ namespace winrt::AutomationChannel::factory_implementation {
39
+
40
+ struct CommandHandler : CommandHandlerT<CommandHandler, implementation::CommandHandler> {};
41
+
42
+ } // namespace winrt::AutomationChannel::factory_implementation
@@ -0,0 +1,25 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+
4
+ namespace AutomationChannel {
5
+
6
+ delegate void SyncAction(Windows.Data.Json.JsonValue args);
7
+ delegate Windows.Data.Json.IJsonValue SyncOperation(Windows.Data.Json.JsonValue args);
8
+ delegate Windows.Foundation.IAsyncAction AsyncAction(Windows.Data.Json.JsonValue args);
9
+ delegate Windows.Foundation.IAsyncOperation<Windows.Data.Json.IJsonValue> AsyncOperation(Windows.Data.Json.JsonValue args);
10
+
11
+ [webhosthidden]
12
+ [default_interface]
13
+ runtimeclass CommandHandler
14
+ {
15
+ CommandHandler();
16
+
17
+ CommandHandler BindAction(String methodName, SyncAction action);
18
+ CommandHandler BindAsyncAction(String methodName, AsyncAction action);
19
+ CommandHandler BindOperation(String methodName, SyncOperation operation);
20
+ CommandHandler BindAsyncOperation(String methodName, AsyncOperation operation);
21
+
22
+ // May throw on delegate error
23
+ Windows.Foundation.IAsyncOperation<Windows.Data.Json.IJsonValue> Invoke(String methodName, Windows.Data.Json.JsonValue params);
24
+ };
25
+ }
@@ -0,0 +1,43 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+ #pragma once
4
+
5
+ #include <winrt/base.h>
6
+ #include <coroutine>
7
+
8
+ // Copied from "vnext\Shared\Utils\CppWinrtLessExceptions.h" until we have a good way to share between packages
9
+
10
+ namespace winrt::AutomationChannel {
11
+
12
+ template <typename Async>
13
+ struct lessthrow_await_adapter {
14
+ Async const &async;
15
+
16
+ bool await_ready() const {
17
+ return async.Status() == winrt::Windows::Foundation::AsyncStatus::Completed;
18
+ }
19
+
20
+ void await_suspend(std::coroutine_handle<> handle) const {
21
+ auto context = winrt::capture<winrt::impl::IContextCallback>(WINRT_IMPL_CoGetObjectContext);
22
+
23
+ async.Completed([handle, context = std::move(context)](auto const &, winrt::Windows::Foundation::AsyncStatus) {
24
+ winrt::impl::com_callback_args args{};
25
+ args.data = handle.address();
26
+
27
+ auto callback = [](winrt::impl::com_callback_args *args) noexcept -> int32_t {
28
+ std::coroutine_handle<>::from_address(args->data)();
29
+ return S_OK;
30
+ };
31
+
32
+ winrt::check_hresult(context->ContextCallback(
33
+ callback, &args, winrt::guid_of<winrt::impl::ICallbackWithNoReentrancyToApplicationSTA>(), 5, nullptr));
34
+ });
35
+ }
36
+
37
+ void await_resume() const {
38
+ // Don't check for a failure result here
39
+ return;
40
+ }
41
+ };
42
+
43
+ } // namespace winrt::AutomationChannel
@@ -0,0 +1,97 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+
4
+ #include "pch.h"
5
+ #include "JsonRpcRequestProcessor.h"
6
+
7
+ #include <winrt/Windows.Data.Json.h>
8
+
9
+ using namespace winrt::Windows::Data::Json;
10
+ using namespace winrt::Windows::Foundation;
11
+ using namespace winrt::Windows::Storage::Streams;
12
+
13
+ namespace winrt::AutomationChannel {
14
+
15
+ JsonRpcRequestProcessor::JsonRpcRequestProcessor(const AutomationChannel::CommandHandler &handler) noexcept
16
+ : m_handler(handler) {}
17
+
18
+ winrt::fire_and_forget JsonRpcRequestProcessor::HandleRequest(
19
+ winrt::hstring requestBody,
20
+ IOutputStream output) noexcept {
21
+ auto handler{m_handler};
22
+
23
+ auto message = co_await DecodeAndValidateMessage(requestBody, output);
24
+ if (!message) {
25
+ co_return;
26
+ }
27
+
28
+ // Cannot co_await to emit failure inside catch block. Keep vars outside scope.
29
+ winrt::hstring errorMessage;
30
+
31
+ try {
32
+ auto result = co_await handler.Invoke(message.GetNamedString(L"method"), message.GetNamedValue(L"params"));
33
+ co_await EmitResult(result, message.GetNamedValue(L"id"), output);
34
+ co_return;
35
+ } catch (const winrt::hresult_error &ex) {
36
+ errorMessage = ex.message();
37
+ } catch (const std::exception &ex) {
38
+ errorMessage = winrt::to_hstring(ex.what());
39
+ }
40
+
41
+ co_await EmitError(JsonRpcErrorCode::InternalError, errorMessage, message.GetNamedValue(L"id"), output);
42
+ }
43
+
44
+ IAsyncOperation<JsonObject> JsonRpcRequestProcessor::DecodeAndValidateMessage(
45
+ winrt::hstring requestBody,
46
+ IOutputStream output) noexcept {
47
+ IOutputStream out(output);
48
+
49
+ JsonObject obj;
50
+ if (!JsonObject::TryParse(requestBody, obj)) {
51
+ co_await EmitError(
52
+ JsonRpcErrorCode::ParseError, L"Could not parse request JSON.", JsonValue::CreateNullValue(), out);
53
+ co_return nullptr;
54
+ }
55
+
56
+ // TODO #7108 validate fields
57
+ co_return obj;
58
+ }
59
+
60
+ IAsyncAction JsonRpcRequestProcessor::EmitError(
61
+ JsonRpcErrorCode code,
62
+ winrt::hstring message,
63
+ JsonValue id,
64
+ IOutputStream output) noexcept {
65
+ JsonObject err;
66
+ err.SetNamedValue(L"code", JsonValue::CreateNumberValue(static_cast<int32_t>(code)));
67
+ err.SetNamedValue(L"message", JsonValue::CreateStringValue(message));
68
+ co_await EmitResponse(err, id, output);
69
+ }
70
+
71
+ IAsyncAction JsonRpcRequestProcessor::EmitResult(IJsonValue result, JsonValue id, IOutputStream output) noexcept {
72
+ JsonObject res;
73
+ res.SetNamedValue(L"result", result);
74
+ co_await EmitResponse(res, id, output);
75
+ }
76
+
77
+ IAsyncAction
78
+ JsonRpcRequestProcessor::EmitResponse(JsonObject responseBody, JsonValue id, IOutputStream output) noexcept {
79
+ responseBody.SetNamedValue(L"jsonrpc", JsonValue::CreateStringValue(L"2.0"));
80
+ responseBody.SetNamedValue(L"id", id);
81
+
82
+ auto utf16JsonString = responseBody.Stringify();
83
+ auto utf8JsonString = winrt::to_string(utf16JsonString);
84
+ winrt::array_view<uint8_t> utf8JsonStringBytes(
85
+ reinterpret_cast<uint8_t *>(utf8JsonString.data()),
86
+ reinterpret_cast<uint8_t *>(utf8JsonString.data() + utf8JsonString.size()));
87
+
88
+ DataWriter writer(output);
89
+ writer.ByteOrder(ByteOrder::LittleEndian);
90
+ writer.WriteUInt32(static_cast<uint32_t>(utf8JsonString.size()));
91
+ writer.WriteBytes(utf8JsonStringBytes);
92
+
93
+ co_await writer.StoreAsync();
94
+ writer.DetachStream();
95
+ }
96
+
97
+ } // namespace winrt::AutomationChannel
@@ -0,0 +1,52 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+ #pragma once
4
+
5
+ #include "CommandHandler.g.h"
6
+
7
+ #include <winrt/Windows.Storage.Streams.h>
8
+
9
+ namespace winrt::AutomationChannel {
10
+
11
+ //! Predefined error codes for the JSON-RPC Spec
12
+ //! See https://www.jsonrpc.org/specification
13
+ enum class JsonRpcErrorCode : int32_t {
14
+ ParseError = -32700,
15
+ InvalidRequest = -32600,
16
+ MethodNotFound = -32601,
17
+ InvalidParams = -32602,
18
+ InternalError = -32603,
19
+ };
20
+
21
+ //! Translates/verifies JSON-RPC2 messages, dispatches them, then outputs the result
22
+ class JsonRpcRequestProcessor final {
23
+ public:
24
+ JsonRpcRequestProcessor(const AutomationChannel::CommandHandler &handler) noexcept;
25
+
26
+ winrt::fire_and_forget HandleRequest(
27
+ winrt::hstring requestBody,
28
+ Windows::Storage::Streams::IOutputStream output) noexcept;
29
+
30
+ private:
31
+ Windows::Foundation::IAsyncOperation<Windows::Data::Json::JsonObject> DecodeAndValidateMessage(
32
+ winrt::hstring requestBody,
33
+ Windows::Storage::Streams::IOutputStream output) noexcept;
34
+
35
+ Windows::Foundation::IAsyncAction EmitError(
36
+ JsonRpcErrorCode code,
37
+ winrt::hstring message,
38
+ Windows::Data::Json::JsonValue id,
39
+ Windows::Storage::Streams::IOutputStream output) noexcept;
40
+ Windows::Foundation::IAsyncAction EmitResult(
41
+ Windows::Data::Json::IJsonValue result,
42
+ Windows::Data::Json::JsonValue id,
43
+ Windows::Storage::Streams::IOutputStream output) noexcept;
44
+ Windows::Foundation::IAsyncAction EmitResponse(
45
+ Windows::Data::Json::JsonObject responseBody,
46
+ Windows::Data::Json::JsonValue id,
47
+ Windows::Storage::Streams::IOutputStream output) noexcept;
48
+
49
+ AutomationChannel::CommandHandler m_handler;
50
+ };
51
+
52
+ } // namespace winrt::AutomationChannel
@@ -0,0 +1,16 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3
+ <ImportGroup Label="PropertySheets" />
4
+ <PropertyGroup Label="UserMacros" />
5
+ <!--
6
+ To customize common C++/WinRT project properties:
7
+ * right-click the project node
8
+ * expand the Common Properties item
9
+ * select the C++/WinRT property page
10
+
11
+ For more advanced scenarios, and complete documentation, please see:
12
+ https://github.com/Microsoft/xlang/tree/master/src/package/cppwinrt/nuget
13
+ -->
14
+ <PropertyGroup />
15
+ <ItemDefinitionGroup />
16
+ </Project>
@@ -0,0 +1,15 @@
1
+ #include "pch.h"
2
+ #include "ReactPackageProvider.h"
3
+ #if __has_include("ReactPackageProvider.g.cpp")
4
+ #include "ReactPackageProvider.g.cpp"
5
+ #endif
6
+
7
+ using namespace winrt::Microsoft::ReactNative;
8
+
9
+ namespace winrt::AutomationChannel::implementation {
10
+
11
+ void ReactPackageProvider::CreatePackage(IReactPackageBuilder const & /*packageBuilder*/) noexcept {
12
+ // Noop
13
+ }
14
+
15
+ } // namespace winrt::AutomationChannel::implementation
@@ -0,0 +1,18 @@
1
+ #pragma once
2
+ #include "ReactPackageProvider.g.h"
3
+
4
+ using namespace winrt::Microsoft::ReactNative;
5
+
6
+ namespace winrt::AutomationChannel::implementation {
7
+ struct ReactPackageProvider : ReactPackageProviderT<ReactPackageProvider> {
8
+ ReactPackageProvider() = default;
9
+
10
+ void CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept;
11
+ };
12
+ } // namespace winrt::AutomationChannel::implementation
13
+
14
+ namespace winrt::AutomationChannel::factory_implementation {
15
+
16
+ struct ReactPackageProvider : ReactPackageProviderT<ReactPackageProvider, implementation::ReactPackageProvider> {};
17
+
18
+ } // namespace winrt::AutomationChannel::factory_implementation
@@ -0,0 +1,12 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+
4
+ namespace AutomationChannel
5
+ {
6
+ [webhosthidden]
7
+ [default_interface]
8
+ runtimeclass ReactPackageProvider : Microsoft.ReactNative.IReactPackageProvider
9
+ {
10
+ ReactPackageProvider();
11
+ };
12
+ }
@@ -0,0 +1,135 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+
4
+ #include "pch.h"
5
+ #include "Server.h"
6
+ #include "Server.g.cpp"
7
+ #include "CppWinrtLessExceptions.h"
8
+
9
+ using namespace winrt::Windows::Foundation;
10
+ using namespace winrt::Windows::Networking;
11
+ using namespace winrt::Windows::Networking::Sockets;
12
+ using namespace winrt::Windows::Storage::Streams;
13
+
14
+ namespace winrt::AutomationChannel::implementation {
15
+ Server::Server(const winrt::AutomationChannel::CommandHandler &handler) : m_requestProcessor(handler) {}
16
+
17
+ IAsyncAction Server::ProcessAllClientRequests(uint16_t port, Windows::Foundation::TimeSpan pollInterval) noexcept {
18
+ auto weakServer = get_weak();
19
+ auto cancellationToken = co_await get_cancellation_token();
20
+
21
+ while (!cancellationToken()) {
22
+ auto strongServer = weakServer.get();
23
+ if (!strongServer) {
24
+ co_return;
25
+ }
26
+
27
+ strongServer->m_socket = StreamSocket();
28
+ auto connection = strongServer->m_socket.ConnectAsync(HostName(L"127.0.0.1"), winrt::to_hstring(port));
29
+ co_await lessthrow_await_adapter<IAsyncAction>{connection};
30
+
31
+ auto hr = connection.ErrorCode();
32
+ if (SUCCEEDED(hr)) {
33
+ break;
34
+ }
35
+
36
+ if (!IsPollContinueCondition(hr)) {
37
+ throw winrt::hresult_error(hr);
38
+ }
39
+
40
+ winrt::apartment_context context;
41
+ co_await pollInterval;
42
+ co_await context;
43
+ }
44
+
45
+ IAsyncAction pumpRequestsCoro(nullptr);
46
+
47
+ // Make sure to let the server die while pumping. Do not keep a strong ref
48
+ // after starting the coroutine
49
+ if (auto strongServer = weakServer.get()) {
50
+ if (!cancellationToken()) {
51
+ pumpRequestsCoro = strongServer->PumpRequests();
52
+ }
53
+ }
54
+
55
+ if (pumpRequestsCoro) {
56
+ cancellationToken.callback([pumpRequestsCoro]() noexcept { pumpRequestsCoro.Cancel(); });
57
+ co_await pumpRequestsCoro;
58
+ }
59
+ }
60
+
61
+ IAsyncAction Server::PumpRequests() noexcept {
62
+ DataReader reader(m_socket.InputStream());
63
+ reader.ByteOrder(ByteOrder::LittleEndian);
64
+ reader.UnicodeEncoding(UnicodeEncoding::Utf8);
65
+
66
+ auto weakServer = get_weak();
67
+ auto cancellationToken = co_await get_cancellation_token();
68
+
69
+ while (!cancellationToken()) {
70
+ auto loadSize = reader.LoadAsync(sizeof(uint32_t));
71
+ co_await lessthrow_await_adapter<DataReaderLoadOperation>{loadSize};
72
+ auto loadSizeHr = loadSize.ErrorCode();
73
+
74
+ if (FAILED(loadSizeHr)) {
75
+ if (IsExpectedConnectionEnd(loadSizeHr)) {
76
+ co_return;
77
+ } else {
78
+ throw winrt::hresult_error(loadSizeHr);
79
+ }
80
+ }
81
+
82
+ auto messageSize = reader.ReadUInt32();
83
+
84
+ auto loadMessage = reader.LoadAsync(messageSize);
85
+ co_await lessthrow_await_adapter<DataReaderLoadOperation>{loadMessage};
86
+ auto loadMessageHr = loadMessage.ErrorCode();
87
+
88
+ if (FAILED(loadMessageHr)) {
89
+ if (IsExpectedConnectionEnd(loadMessageHr)) {
90
+ co_return;
91
+ } else {
92
+ throw winrt::hresult_error(loadMessageHr);
93
+ }
94
+ }
95
+
96
+ auto message = reader.ReadString(messageSize);
97
+
98
+ if (auto strongServer = weakServer.get()) {
99
+ if (!cancellationToken()) {
100
+ strongServer->m_requestProcessor.HandleRequest(message, strongServer->m_socket.OutputStream());
101
+ }
102
+ }
103
+ }
104
+ }
105
+
106
+ bool Server::IsPollContinueCondition(winrt::hresult hr) noexcept {
107
+ auto socketError = SocketError::GetStatus(hr);
108
+
109
+ switch (socketError) {
110
+ case SocketErrorStatus::ConnectionTimedOut:
111
+ case SocketErrorStatus::ConnectionRefused:
112
+ case SocketErrorStatus::HostIsDown:
113
+ case SocketErrorStatus::HostNotFound:
114
+ return true;
115
+
116
+ default:
117
+ return false;
118
+ }
119
+ }
120
+
121
+ bool Server::IsExpectedConnectionEnd(winrt::hresult hr) noexcept {
122
+ auto socketError = SocketError::GetStatus(hr);
123
+
124
+ switch (socketError) {
125
+ case SocketErrorStatus::OperationAborted:
126
+ case SocketErrorStatus::ConnectionResetByPeer:
127
+ case SocketErrorStatus::SoftwareCausedConnectionAbort:
128
+ return true;
129
+
130
+ default:
131
+ return false;
132
+ }
133
+ }
134
+
135
+ } // namespace winrt::AutomationChannel::implementation
@@ -0,0 +1,34 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+
4
+ #pragma once
5
+ #include "Server.g.h"
6
+ #include "JsonRpcRequestProcessor.h"
7
+
8
+ #include <winrt/Windows.Networking.Sockets.h>
9
+
10
+ namespace winrt::AutomationChannel::implementation {
11
+
12
+ struct Server : ServerT<Server> {
13
+ Server(const AutomationChannel::CommandHandler &handler);
14
+ Windows::Foundation::IAsyncAction ProcessAllClientRequests(
15
+ uint16_t port,
16
+ Windows::Foundation::TimeSpan pollInterval) noexcept;
17
+
18
+ private:
19
+ bool IsPollContinueCondition(winrt::hresult hr) noexcept;
20
+ bool IsExpectedConnectionEnd(winrt::hresult hr) noexcept;
21
+
22
+ Windows::Foundation::IAsyncAction PumpRequests() noexcept;
23
+
24
+ JsonRpcRequestProcessor m_requestProcessor;
25
+ Windows::Networking::Sockets::StreamSocket m_socket;
26
+ };
27
+
28
+ } // namespace winrt::AutomationChannel::implementation
29
+
30
+ namespace winrt::AutomationChannel::factory_implementation {
31
+
32
+ struct Server : ServerT<Server, implementation::Server> {};
33
+
34
+ } // namespace winrt::AutomationChannel::factory_implementation
@@ -0,0 +1,20 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+
4
+ import "CommandHandler.idl";
5
+
6
+ namespace AutomationChannel {
7
+
8
+ [webhosthidden]
9
+ [default_interface]
10
+ runtimeclass Server
11
+ {
12
+ // Construct the server. Does not start listening/polling.
13
+ Server(AutomationChannel.CommandHandler handler);
14
+
15
+ // Poll, waiting for a client to connect to the application. Process all
16
+ // of the single clients request, then complete the AsyncAction
17
+ Windows.Foundation.IAsyncAction ProcessAllClientRequests(UInt16 port, Windows.Foundation.TimeSpan pollInterval);
18
+ };
19
+
20
+ }
@@ -0,0 +1,4 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+
4
+ #include "pch.h"
@@ -0,0 +1,13 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+
4
+ #pragma once
5
+
6
+ #define NOMINMAX
7
+
8
+ #include <windows.h>
9
+ #include <winrt/Microsoft.ReactNative.h>
10
+ #include <winrt/Windows.Data.Json.h>
11
+ #include <winrt/Windows.Foundation.Collections.h>
12
+ #include <winrt/Windows.Foundation.h>
13
+ #include <winrt/Windows.Storage.Streams.h>
@@ -0,0 +1,151 @@
1
+ 
2
+ Microsoft Visual Studio Solution File, Format Version 12.00
3
+ # Visual Studio Version 17
4
+ VisualStudioVersion = 17.3.32929.385
5
+ MinimumVisualStudioVersion = 10.0.40219.1
6
+ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AutomationChannel", "AutomationChannel\AutomationChannel.vcxproj", "{C0A69310-6119-46DC-A6D6-0BAB7826DC92}"
7
+ ProjectSection(ProjectDependencies) = postProject
8
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {F7D32BD0-2749-483E-9A0D-1635EF7E3136}
9
+ EndProjectSection
10
+ EndProject
11
+ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Folly", "..\..\..\..\vnext\Folly\Folly.vcxproj", "{A990658C-CE31-4BCC-976F-0FC6B1AF693D}"
12
+ EndProject
13
+ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fmt", "..\..\..\..\vnext\fmt\fmt.vcxproj", "{14B93DC8-FD93-4A6D-81CB-8BC96644501C}"
14
+ EndProject
15
+ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReactCommon", "..\..\..\..\vnext\ReactCommon\ReactCommon.vcxproj", "{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}"
16
+ ProjectSection(ProjectDependencies) = postProject
17
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {A990658C-CE31-4BCC-976F-0FC6B1AF693D}
18
+ EndProjectSection
19
+ EndProject
20
+ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative", "..\..\..\..\vnext\Microsoft.ReactNative\Microsoft.ReactNative.vcxproj", "{F7D32BD0-2749-483E-9A0D-1635EF7E3136}"
21
+ EndProject
22
+ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative.Cxx", "..\..\..\..\vnext\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems", "{DA8B35B3-DA00-4B02-BDE6-6A397B3FD46B}"
23
+ EndProject
24
+ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Common", "..\..\..\..\vnext\Common\Common.vcxproj", "{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}"
25
+ EndProject
26
+ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ReactNative", "ReactNative", "{5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}"
27
+ EndProject
28
+ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative.Shared", "..\..\..\..\vnext\Shared\Shared.vcxitems", "{2049DBE9-8D13-42C9-AE4B-413AE38FFFD0}"
29
+ EndProject
30
+ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Mso", "..\..\..\..\vnext\Mso\Mso.vcxitems", "{84E05BFA-CBAF-4F0D-BFB6-4CE85742A57E}"
31
+ EndProject
32
+ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Include", "..\..\..\..\vnext\include\Include.vcxitems", "{EF074BA1-2D54-4D49-A28E-5E040B47CD2E}"
33
+ EndProject
34
+ Global
35
+ GlobalSection(SharedMSBuildProjectFiles) = preSolution
36
+ ..\..\..\..\vnext\Shared\Shared.vcxitems*{2049dbe9-8d13-42c9-ae4b-413ae38fffd0}*SharedItemsImports = 9
37
+ ..\..\..\..\vnext\Mso\Mso.vcxitems*{84e05bfa-cbaf-4f0d-bfb6-4ce85742a57e}*SharedItemsImports = 9
38
+ ..\..\..\..\vnext\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{da8b35b3-da00-4b02-bde6-6a397b3fd46b}*SharedItemsImports = 9
39
+ ..\..\..\..\vnext\include\Include.vcxitems*{ef074ba1-2d54-4d49-a28e-5e040b47cd2e}*SharedItemsImports = 9
40
+ ..\..\..\..\vnext\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4
41
+ ..\..\..\..\vnext\Mso\Mso.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4
42
+ ..\..\..\..\vnext\Shared\Shared.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4
43
+ EndGlobalSection
44
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
45
+ Debug|ARM64 = Debug|ARM64
46
+ Debug|x64 = Debug|x64
47
+ Debug|x86 = Debug|x86
48
+ Release|ARM64 = Release|ARM64
49
+ Release|x64 = Release|x64
50
+ Release|x86 = Release|x86
51
+ EndGlobalSection
52
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
53
+ {C0A69310-6119-46DC-A6D6-0BAB7826DC92}.Debug|ARM64.ActiveCfg = Debug|ARM64
54
+ {C0A69310-6119-46DC-A6D6-0BAB7826DC92}.Debug|ARM64.Build.0 = Debug|ARM64
55
+ {C0A69310-6119-46DC-A6D6-0BAB7826DC92}.Debug|ARM64.Deploy.0 = Debug|ARM64
56
+ {C0A69310-6119-46DC-A6D6-0BAB7826DC92}.Debug|x64.ActiveCfg = Debug|x64
57
+ {C0A69310-6119-46DC-A6D6-0BAB7826DC92}.Debug|x64.Build.0 = Debug|x64
58
+ {C0A69310-6119-46DC-A6D6-0BAB7826DC92}.Debug|x64.Deploy.0 = Debug|x64
59
+ {C0A69310-6119-46DC-A6D6-0BAB7826DC92}.Debug|x86.ActiveCfg = Debug|Win32
60
+ {C0A69310-6119-46DC-A6D6-0BAB7826DC92}.Debug|x86.Build.0 = Debug|Win32
61
+ {C0A69310-6119-46DC-A6D6-0BAB7826DC92}.Debug|x86.Deploy.0 = Debug|Win32
62
+ {C0A69310-6119-46DC-A6D6-0BAB7826DC92}.Release|ARM64.ActiveCfg = Release|ARM64
63
+ {C0A69310-6119-46DC-A6D6-0BAB7826DC92}.Release|ARM64.Build.0 = Release|ARM64
64
+ {C0A69310-6119-46DC-A6D6-0BAB7826DC92}.Release|ARM64.Deploy.0 = Release|ARM64
65
+ {C0A69310-6119-46DC-A6D6-0BAB7826DC92}.Release|x64.ActiveCfg = Release|x64
66
+ {C0A69310-6119-46DC-A6D6-0BAB7826DC92}.Release|x64.Build.0 = Release|x64
67
+ {C0A69310-6119-46DC-A6D6-0BAB7826DC92}.Release|x64.Deploy.0 = Release|x64
68
+ {C0A69310-6119-46DC-A6D6-0BAB7826DC92}.Release|x86.ActiveCfg = Release|Win32
69
+ {C0A69310-6119-46DC-A6D6-0BAB7826DC92}.Release|x86.Build.0 = Release|Win32
70
+ {C0A69310-6119-46DC-A6D6-0BAB7826DC92}.Release|x86.Deploy.0 = Release|Win32
71
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.ActiveCfg = Debug|ARM64
72
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.Build.0 = Debug|ARM64
73
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.ActiveCfg = Debug|x64
74
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.Build.0 = Debug|x64
75
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.ActiveCfg = Debug|Win32
76
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.Build.0 = Debug|Win32
77
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.ActiveCfg = Release|ARM64
78
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.Build.0 = Release|ARM64
79
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.ActiveCfg = Release|x64
80
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.Build.0 = Release|x64
81
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.ActiveCfg = Release|Win32
82
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.Build.0 = Release|Win32
83
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.ActiveCfg = Debug|ARM64
84
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.Build.0 = Debug|ARM64
85
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x64.ActiveCfg = Debug|x64
86
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x64.Build.0 = Debug|x64
87
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x86.ActiveCfg = Debug|Win32
88
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x86.Build.0 = Debug|Win32
89
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|ARM64.ActiveCfg = Release|ARM64
90
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|ARM64.Build.0 = Release|ARM64
91
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x64.ActiveCfg = Release|x64
92
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x64.Build.0 = Release|x64
93
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x86.ActiveCfg = Release|Win32
94
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x86.Build.0 = Release|Win32
95
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|ARM64.ActiveCfg = Debug|ARM64
96
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|ARM64.Build.0 = Debug|ARM64
97
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x64.ActiveCfg = Debug|x64
98
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x64.Build.0 = Debug|x64
99
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x86.ActiveCfg = Debug|Win32
100
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x86.Build.0 = Debug|Win32
101
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|ARM64.ActiveCfg = Release|ARM64
102
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|ARM64.Build.0 = Release|ARM64
103
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x64.ActiveCfg = Release|x64
104
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x64.Build.0 = Release|x64
105
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x86.ActiveCfg = Release|Win32
106
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x86.Build.0 = Release|Win32
107
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|ARM64.ActiveCfg = Debug|ARM64
108
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|ARM64.Build.0 = Debug|ARM64
109
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x64.ActiveCfg = Debug|x64
110
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x64.Build.0 = Debug|x64
111
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x86.ActiveCfg = Debug|Win32
112
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x86.Build.0 = Debug|Win32
113
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|ARM64.ActiveCfg = Release|ARM64
114
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|ARM64.Build.0 = Release|ARM64
115
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x64.ActiveCfg = Release|x64
116
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x64.Build.0 = Release|x64
117
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x86.ActiveCfg = Release|Win32
118
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x86.Build.0 = Release|Win32
119
+ {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|ARM64.ActiveCfg = Debug|ARM64
120
+ {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|ARM64.Build.0 = Debug|ARM64
121
+ {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x64.ActiveCfg = Debug|x64
122
+ {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x64.Build.0 = Debug|x64
123
+ {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x86.ActiveCfg = Debug|Win32
124
+ {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x86.Build.0 = Debug|Win32
125
+ {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x86.Deploy.0 = Debug|Win32
126
+ {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|ARM64.ActiveCfg = Release|ARM64
127
+ {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|ARM64.Build.0 = Release|ARM64
128
+ {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x64.ActiveCfg = Release|x64
129
+ {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x64.Build.0 = Release|x64
130
+ {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x86.ActiveCfg = Release|Win32
131
+ {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x86.Build.0 = Release|Win32
132
+ {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x86.Deploy.0 = Release|Win32
133
+ EndGlobalSection
134
+ GlobalSection(SolutionProperties) = preSolution
135
+ HideSolutionNode = FALSE
136
+ EndGlobalSection
137
+ GlobalSection(NestedProjects) = preSolution
138
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
139
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
140
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
141
+ {DA8B35B3-DA00-4B02-BDE6-6A397B3FD46B} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
142
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
143
+ {2049DBE9-8D13-42C9-AE4B-413AE38FFFD0} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
144
+ {84E05BFA-CBAF-4F0D-BFB6-4CE85742A57E} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
145
+ {EF074BA1-2D54-4D49-A28E-5E040B47CD2E} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
146
+ {14B93DC8-FD93-4A6D-81CB-8BC96644501C} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
147
+ EndGlobalSection
148
+ GlobalSection(ExtensibilityGlobals) = postSolution
149
+ SolutionGuid = {D43FAD39-F619-437D-BB40-04A3982ACB6A}
150
+ EndGlobalSection
151
+ EndGlobal
@@ -0,0 +1,11 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3
+
4
+ <PropertyGroup Label="Microsoft.ReactNative Experimental Features">
5
+ <RnwNewArch>false</RnwNewArch>
6
+ <UseExperimentalNuget>false</UseExperimentalNuget>
7
+
8
+ <ReactExperimentalFeaturesSet>true</ReactExperimentalFeaturesSet>
9
+ </PropertyGroup>
10
+
11
+ </Project>