@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 +56 -0
- package/lib-commonjs/automationChannel.d.ts +32 -0
- package/lib-commonjs/automationChannel.js +122 -0
- package/lib-commonjs/automationChannel.js.map +1 -0
- package/package.json +59 -0
- package/windows/AutomationChannel/AutomationChannel.def +3 -0
- package/windows/AutomationChannel/AutomationChannel.filters +22 -0
- package/windows/AutomationChannel/AutomationChannel.vcxproj +154 -0
- package/windows/AutomationChannel/CommandHandler.cpp +91 -0
- package/windows/AutomationChannel/CommandHandler.h +42 -0
- package/windows/AutomationChannel/CommandHandler.idl +25 -0
- package/windows/AutomationChannel/CppWinrtLessExceptions.h +43 -0
- package/windows/AutomationChannel/JsonRpcRequestProcessor.cpp +97 -0
- package/windows/AutomationChannel/JsonRpcRequestProcessor.h +52 -0
- package/windows/AutomationChannel/PropertySheet.props +16 -0
- package/windows/AutomationChannel/ReactPackageProvider.cpp +15 -0
- package/windows/AutomationChannel/ReactPackageProvider.h +18 -0
- package/windows/AutomationChannel/ReactPackageProvider.idl +12 -0
- package/windows/AutomationChannel/Server.cpp +135 -0
- package/windows/AutomationChannel/Server.h +34 -0
- package/windows/AutomationChannel/Server.idl +20 -0
- package/windows/AutomationChannel/pch.cpp +4 -0
- package/windows/AutomationChannel/pch.h +13 -0
- package/windows/AutomationChannel.sln +151 -0
- package/windows/ExperimentalFeatures.props +11 -0
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,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 ¶ms) {
|
|
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 ¶ms);
|
|
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,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>
|