@rustwirebot/rustplus.js 2.5.0

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.
Files changed (42) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +351 -0
  3. package/camera.js +425 -0
  4. package/cli/index.js +308 -0
  5. package/cli/pair.html +49 -0
  6. package/docs/API.md +101 -0
  7. package/docs/DownloadBundle.md +7 -0
  8. package/docs/PairingFlow.md +19 -0
  9. package/donate.md +10 -0
  10. package/examples/10_shoot_autoturret.js +100 -0
  11. package/examples/1_send_team_chat.js +16 -0
  12. package/examples/2_turn_smart_switch_on.js +21 -0
  13. package/examples/3_turn_smart_switch_off.js +21 -0
  14. package/examples/4_entity_changed_broadcasts.js +58 -0
  15. package/examples/5_download_map_jpeg.js +22 -0
  16. package/examples/6_async_requests.js +35 -0
  17. package/examples/7_render_camera.js +34 -0
  18. package/examples/8_move_ptz_camera.js +56 -0
  19. package/examples/9_zoom_ptz_camera.js +37 -0
  20. package/package.json +48 -0
  21. package/rustplus.js +380 -0
  22. package/rustplus.js.svg +34 -0
  23. package/rustplus.proto +431 -0
  24. package/vendor/push-receiver/LICENSE +21 -0
  25. package/vendor/push-receiver/NOTICE.md +32 -0
  26. package/vendor/push-receiver/android/fcm.js +134 -0
  27. package/vendor/push-receiver/client.js +216 -0
  28. package/vendor/push-receiver/constants.js +53 -0
  29. package/vendor/push-receiver/fcm/index.js +52 -0
  30. package/vendor/push-receiver/fcm/server-key/index.js +67 -0
  31. package/vendor/push-receiver/gcm/android_checkin.proto +96 -0
  32. package/vendor/push-receiver/gcm/checkin.proto +155 -0
  33. package/vendor/push-receiver/gcm/index.js +128 -0
  34. package/vendor/push-receiver/index.js +17 -0
  35. package/vendor/push-receiver/mcs.proto +328 -0
  36. package/vendor/push-receiver/parser.js +276 -0
  37. package/vendor/push-receiver/register/index.js +18 -0
  38. package/vendor/push-receiver/utils/base64/index.js +15 -0
  39. package/vendor/push-receiver/utils/decrypt/index.js +23 -0
  40. package/vendor/push-receiver/utils/http-request/index.js +43 -0
  41. package/vendor/push-receiver/utils/request/index.js +27 -0
  42. package/vendor/push-receiver/utils/timeout/index.js +7 -0
@@ -0,0 +1,58 @@
1
+ const RustPlus = require('@rustwirebot/rustplus.js');
2
+ var rustplus = new RustPlus('ip', 'port', 'playerId', 'playerToken');
3
+
4
+ // wait until connected before sending commands
5
+ rustplus.on('connected', () => {
6
+
7
+ /**
8
+ * getting an entities info will cause the rust server
9
+ * to send an entity changed broadcast each time the
10
+ * entities state changes.
11
+ */
12
+ rustplus.getEntityInfo(1234567, (message) => {
13
+
14
+ /**
15
+ * you can of course see the current entity state in this callback
16
+ * as a 'one off' check. But broadcasts will still be sent.
17
+ */
18
+ console.log("getEntityInfo result: " + JSON.stringify(message));
19
+
20
+ /**
21
+ * we won't disconnect from the rust server in this example
22
+ * as we want to receive broadcasts in the message handler below.
23
+ */
24
+ // rustplus.disconnect();
25
+
26
+ });
27
+
28
+ });
29
+
30
+ // listen for messages from rust server
31
+ rustplus.on('message', (message) => {
32
+
33
+ // check if message is an entity changed broadcast
34
+ if(message.broadcast && message.broadcast.entityChanged){
35
+
36
+ /**
37
+ * since we called getEntityInfo, this message handler will be triggered
38
+ * when the entity state has changed. for example, when a smart alarm is triggered,
39
+ * a smart switch is toggled or a storage monitor has updated.
40
+ */
41
+
42
+ var entityChanged = message.broadcast.entityChanged;
43
+
44
+ // log the broadcast
45
+ console.log(message.broadcast);
46
+
47
+ var entityId = entityChanged.entityId;
48
+ var value = entityChanged.payload.value;
49
+
50
+ // log the entity status
51
+ console.log("entity " + entityId + " is now " + (value ? "active" : "inactive"));
52
+
53
+ }
54
+
55
+ });
56
+
57
+ // connect to rust server
58
+ rustplus.connect();
@@ -0,0 +1,22 @@
1
+ const fs = require('fs');
2
+ const RustPlus = require('@rustwirebot/rustplus.js');
3
+ var rustplus = new RustPlus('ip', 'port', 'playerId', 'playerToken');
4
+
5
+ // wait until connected before sending commands
6
+ rustplus.on('connected', () => {
7
+
8
+ // get the map
9
+ rustplus.getMap((message) => {
10
+
11
+ // save jpg image of map to file
12
+ fs.writeFileSync('map.jpg', message.response.map.jpgImage);
13
+
14
+ // disconnect from rust server
15
+ rustplus.disconnect();
16
+
17
+ });
18
+
19
+ });
20
+
21
+ // connect to rust server
22
+ rustplus.connect();
@@ -0,0 +1,35 @@
1
+ const RustPlus = require('@rustwirebot/rustplus.js');
2
+ var rustplus = new RustPlus('ip', 'port', 'playerId', 'playerToken');
3
+
4
+ // wait until connected before sending commands
5
+ rustplus.on('connected', () => {
6
+
7
+ /**
8
+ * sendRequestAsync will return a promise for your request.
9
+ * you can optionally pass in a second parameter for the timeout in milliseconds
10
+ * - AppResponse packets will be sent to `then` on success.
11
+ * - AppError packets and Timeout Errors will be sent to `catch`.
12
+ */
13
+ rustplus.sendRequestAsync({
14
+ getInfo: {}, // get server info with a timeout of 2 seconds
15
+ }, 2000).then((response) => {
16
+
17
+ // AppResponse
18
+ console.log(response);
19
+
20
+ }).catch((error) => {
21
+
22
+ // AppError or Error('Timeout');
23
+ console.log(error);
24
+
25
+ }).finally(() => {
26
+
27
+ // disconnect so our script is finished
28
+ rustplus.disconnect();
29
+
30
+ });
31
+
32
+ });
33
+
34
+ // connect to rust server
35
+ rustplus.connect();
@@ -0,0 +1,34 @@
1
+ const RustPlus = require('@rustwirebot/rustplus.js');
2
+ const fs = require("fs");
3
+ var rustplus = new RustPlus('ip', 'port', 'playerId', 'playerToken');
4
+
5
+ rustplus.on('connected', async () => {
6
+
7
+ console.log("connected");
8
+
9
+ // get a camera
10
+ const camera = rustplus.getCamera("DOME1");
11
+
12
+ // listen for events when a camera frame has been rendered, you will get a png image buffer
13
+ camera.on('render', async (frame) => {
14
+
15
+ console.log("on render");
16
+
17
+ // save camera frame to disk
18
+ fs.writeFileSync(`camera.png`, frame);
19
+
20
+ // unsubscribe from camera to allow others to control it
21
+ await camera.unsubscribe();
22
+
23
+ // disconnect from server after a single render
24
+ rustplus.disconnect();
25
+
26
+ });
27
+
28
+ // subscribe to camera
29
+ await camera.subscribe();
30
+
31
+ });
32
+
33
+ // connect to rust server
34
+ rustplus.connect();
@@ -0,0 +1,56 @@
1
+ const RustPlus = require('../rustplus');
2
+ const Camera = require('../camera');
3
+ var rustplus = new RustPlus('ip', 'port', 'playerId', 'playerToken');
4
+
5
+ function delay(time) {
6
+ return new Promise(resolve => setTimeout(resolve, time));
7
+ }
8
+
9
+ rustplus.on('connected', async () => {
10
+
11
+ console.log("connected");
12
+
13
+ // get a camera (must support PTZ)
14
+ const camera = rustplus.getCamera("PTZ1");
15
+
16
+ // wait until subscribed to camera
17
+ camera.on('subscribed', async () => {
18
+
19
+ console.log("subscribed to camera");
20
+
21
+ // move camera up 10 times
22
+ for(let i = 0; i < 10; i++){
23
+ await camera.move(Camera.Buttons.NONE, 0, 1);
24
+ await delay(100);
25
+ }
26
+
27
+ // move camera down 10 times
28
+ for(let i = 0; i < 10; i++){
29
+ await camera.move(Camera.Buttons.NONE, 0, -1);
30
+ await delay(100);
31
+ }
32
+
33
+ // move camera left 10 times
34
+ for(let i = 0; i < 10; i++){
35
+ await camera.move(Camera.Buttons.NONE, -1, 0);
36
+ await delay(100);
37
+ }
38
+
39
+ // move camera right 10 times
40
+ for(let i = 0; i < 10; i++){
41
+ await camera.move(Camera.Buttons.NONE, 1, 0);
42
+ await delay(100);
43
+ }
44
+
45
+ console.log("disconnecting");
46
+ await rustplus.disconnect();
47
+
48
+ });
49
+
50
+ // subscribe to camera
51
+ await camera.subscribe();
52
+
53
+ });
54
+
55
+ // connect to rust server
56
+ rustplus.connect();
@@ -0,0 +1,37 @@
1
+ const RustPlus = require('../rustplus');
2
+ var rustplus = new RustPlus('ip', 'port', 'playerId', 'playerToken');
3
+
4
+ function delay(time) {
5
+ return new Promise(resolve => setTimeout(resolve, time));
6
+ }
7
+
8
+ rustplus.on('connected', async () => {
9
+
10
+ console.log("connected");
11
+
12
+ // get a camera (must support PTZ)
13
+ const camera = rustplus.getCamera("PTZ1");
14
+
15
+ // wait until subscribed to camera
16
+ camera.on('subscribed', async () => {
17
+
18
+ console.log("subscribed to camera");
19
+
20
+ // zoom camera every 1 second, 8 times
21
+ for(let i = 0; i < 8; i++){
22
+ await camera.zoom();
23
+ await delay(1000);
24
+ }
25
+
26
+ console.log("disconnecting");
27
+ await rustplus.disconnect();
28
+
29
+ });
30
+
31
+ // subscribe to camera
32
+ await camera.subscribe();
33
+
34
+ });
35
+
36
+ // connect to rust server
37
+ rustplus.connect();
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@rustwirebot/rustplus.js",
3
+ "version": "2.5.0",
4
+ "description": "NodeJS library for controlling Smart Switches and interacting with the Rust+ Companion API. Maintained fork of @liamcottle/rustplus.js, republished by BotForge Studios / RustWire.",
5
+ "main": "rustplus.js",
6
+ "bin": {
7
+ "rustplus": "./cli/index.js"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/YOUR_GITHUB_USERNAME/rustwire-rustplus.js.git"
12
+ },
13
+ "keywords": [
14
+ "rust",
15
+ "rust+",
16
+ "rustplus",
17
+ "rustplus-api",
18
+ "companion",
19
+ "api",
20
+ "websocket",
21
+ "smart switch",
22
+ "smart alarm",
23
+ "team chat",
24
+ "rustwire"
25
+ ],
26
+ "author": "Liam Cottle",
27
+ "contributors": [
28
+ "BotForge Studios (fork maintainer)"
29
+ ],
30
+ "license": "MIT",
31
+ "bugs": {
32
+ "url": "https://github.com/YOUR_GITHUB_USERNAME/rustwire-rustplus.js/issues"
33
+ },
34
+ "homepage": "https://github.com/YOUR_GITHUB_USERNAME/rustwire-rustplus.js#readme",
35
+ "dependencies": {
36
+ "axios": "^1.2.2",
37
+ "chrome-launcher": "^0.15.0",
38
+ "command-line-args": "^5.2.0",
39
+ "command-line-usage": "^6.1.1",
40
+ "express": "^4.17.1",
41
+ "http_ece": "^1.0.5",
42
+ "jimp": "^0.22.7",
43
+ "long": "^3.2.0",
44
+ "protobufjs": "^7.1.2",
45
+ "uuid": "^11.1.1",
46
+ "ws": "^8.3.0"
47
+ }
48
+ }
package/rustplus.js ADDED
@@ -0,0 +1,380 @@
1
+ "use strict";
2
+
3
+ const path = require('path');
4
+ const WebSocket = require('ws');
5
+ const protobuf = require("protobufjs");
6
+ const { EventEmitter } = require('events');
7
+ const Camera = require('./camera');
8
+
9
+ class RustPlus extends EventEmitter {
10
+
11
+ /**
12
+ * @param server The ip address or hostname of the Rust Server
13
+ * @param port The port of the Rust Server (app.port in server.cfg)
14
+ * @param playerId SteamId of the Player
15
+ * @param playerToken Player Token from Server Pairing
16
+ * @param useFacepunchProxy True to use secure websocket via Facepunch's proxy, or false to directly connect to Rust Server
17
+ *
18
+ * Events emitted by the RustPlus class instance
19
+ * - connecting: When we are connecting to the Rust Server.
20
+ * - connected: When we are connected to the Rust Server.
21
+ * - message: When an AppMessage has been received from the Rust Server.
22
+ * - request: When an AppRequest has been sent to the Rust Server.
23
+ * - disconnected: When we are disconnected from the Rust Server.
24
+ * - error: When something goes wrong.
25
+ */
26
+ constructor(server, port, playerId, playerToken, useFacepunchProxy = false) {
27
+
28
+ super();
29
+
30
+ this.server = server;
31
+ this.port = port;
32
+ this.playerId = playerId;
33
+ this.playerToken = playerToken;
34
+ this.useFacepunchProxy = useFacepunchProxy;
35
+
36
+ this.seq = 0;
37
+ this.seqCallbacks = [];
38
+
39
+ }
40
+
41
+ /**
42
+ * This sets everything up and then connects to the Rust Server via WebSocket.
43
+ */
44
+ connect() {
45
+
46
+ // load protobuf then connect
47
+ protobuf.load(path.resolve(__dirname, "rustplus.proto")).then((root) => {
48
+
49
+ // make sure existing connection is disconnected before connecting again.
50
+ if(this.websocket){
51
+ this.disconnect();
52
+ }
53
+
54
+ // load proto types
55
+ this.AppRequest = root.lookupType("rustplus.AppRequest");
56
+ this.AppMessage = root.lookupType("rustplus.AppMessage");
57
+
58
+ // fire event as we are connecting
59
+ this.emit('connecting');
60
+
61
+ // connect to websocket
62
+ var address = this.useFacepunchProxy ? `wss://companion-rust.facepunch.com/game/${this.server}/${this.port}` : `ws://${this.server}:${this.port}`;
63
+ this.websocket = new WebSocket(address);
64
+
65
+ // fire event when connected
66
+ this.websocket.on('open', () => {
67
+ this.emit('connected');
68
+ });
69
+
70
+ // fire event for websocket errors
71
+ this.websocket.on('error', (e) => {
72
+ this.emit('error', e);
73
+ });
74
+
75
+ this.websocket.on('message', (data) => {
76
+
77
+ // decode received message
78
+ var message = this.AppMessage.decode(data);
79
+
80
+ // check if received message is a response and if we have a callback registered for it
81
+ if(message.response && message.response.seq && this.seqCallbacks[message.response.seq]){
82
+
83
+ // get the callback for the response sequence
84
+ var callback = this.seqCallbacks[message.response.seq];
85
+
86
+ // call the callback with the response message
87
+ var result = callback(message);
88
+
89
+ // remove the callback
90
+ delete this.seqCallbacks[message.response.seq];
91
+
92
+ // if callback returns true, don't fire message event
93
+ if(result){
94
+ return;
95
+ }
96
+
97
+ }
98
+
99
+ // fire message event for received messages that aren't handled by callback
100
+ this.emit('message', this.AppMessage.decode(data));
101
+
102
+ });
103
+
104
+ // fire event when disconnected
105
+ this.websocket.on('close', () => {
106
+ this.emit('disconnected');
107
+ });
108
+
109
+ });
110
+
111
+ }
112
+
113
+ /**
114
+ * Disconnect from the Rust Server.
115
+ */
116
+ disconnect() {
117
+ if(this.websocket){
118
+ this.websocket.terminate();
119
+ this.websocket = null;
120
+ }
121
+ }
122
+
123
+ /**
124
+ * Check if RustPlus is connected to the server.
125
+ * @returns {boolean}
126
+ */
127
+ isConnected() {
128
+ return (this.websocket.readyState === WebSocket.OPEN);
129
+ }
130
+
131
+ /**
132
+ * Send a Request to the Rust Server with an optional callback when a Response is received.
133
+ * @param data this should contain valid data for the AppRequest packet in the rustplus.proto schema file
134
+ * @param callback
135
+ */
136
+ sendRequest(data, callback) {
137
+
138
+ // increment sequence number
139
+ let currentSeq = ++this.seq;
140
+
141
+ // save callback if provided
142
+ if(callback){
143
+ this.seqCallbacks[currentSeq] = callback;
144
+ }
145
+
146
+ // create protobuf from AppRequest packet
147
+ let request = this.AppRequest.fromObject({
148
+ seq: currentSeq,
149
+ playerId: this.playerId,
150
+ playerToken: this.playerToken,
151
+ ...data, // merge in provided data for AppRequest
152
+ });
153
+
154
+ // send AppRequest packet to rust server
155
+ this.websocket.send(this.AppRequest.encode(request).finish());
156
+
157
+ // fire event when request has been sent, this is useful for logging
158
+ this.emit('request', request);
159
+
160
+ }
161
+
162
+ /**
163
+ * Send a Request to the Rust Server and return a Promise
164
+ * @param data this should contain valid data for the AppRequest packet defined in the rustplus.proto schema file
165
+ * @param timeoutMilliseconds milliseconds before the promise will be rejected. Defaults to 10 seconds.
166
+ */
167
+ sendRequestAsync(data, timeoutMilliseconds = 10000) {
168
+ return new Promise((resolve, reject) => {
169
+
170
+ // reject promise after timeout
171
+ var timeout = setTimeout(() => {
172
+ reject(new Error('Timeout reached while waiting for response'));
173
+ }, timeoutMilliseconds);
174
+
175
+ // send request
176
+ this.sendRequest(data, (message) => {
177
+
178
+ // cancel timeout
179
+ clearTimeout(timeout);
180
+
181
+ if(message.response.error){
182
+
183
+ // reject promise if server returns an AppError for this request
184
+ reject(message.response.error);
185
+
186
+ } else {
187
+
188
+ // request was successful, resolve with message.response
189
+ resolve(message.response);
190
+
191
+ }
192
+
193
+ });
194
+
195
+ });
196
+ }
197
+
198
+ /**
199
+ * Send a Request to the Rust Server to set the Entity Value.
200
+ * @param entityId the entity id to set the value for
201
+ * @param value the value to set on the entity
202
+ * @param callback
203
+ */
204
+ setEntityValue(entityId, value, callback) {
205
+ this.sendRequest({
206
+ entityId: entityId,
207
+ setEntityValue: {
208
+ value: value,
209
+ },
210
+ }, callback);
211
+ }
212
+
213
+ /**
214
+ * Turn a Smart Switch On
215
+ * @param entityId the entity id of the smart switch to turn on
216
+ * @param callback
217
+ */
218
+ turnSmartSwitchOn(entityId, callback) {
219
+ this.setEntityValue(entityId, true, callback);
220
+ }
221
+
222
+ /**
223
+ * Turn a Smart Switch Off
224
+ * @param entityId the entity id of the smart switch to turn off
225
+ * @param callback
226
+ */
227
+ turnSmartSwitchOff(entityId, callback) {
228
+ this.setEntityValue(entityId, false, callback);
229
+ }
230
+
231
+ /**
232
+ * Quickly turn on and off a Smart Switch as if it were a Strobe Light.
233
+ * You will get rate limited by the Rust Server after a short period.
234
+ * It was interesting to watch in game though 😝
235
+ */
236
+ strobe(entityId, timeoutMilliseconds = 100, value = true) {
237
+ this.setEntityValue(entityId, value);
238
+ setTimeout(() => {
239
+ this.strobe(entityId, timeoutMilliseconds, !value);
240
+ }, timeoutMilliseconds);
241
+ }
242
+
243
+ /**
244
+ * Send a message to Team Chat
245
+ * @param message the message to send to team chat
246
+ * @param callback
247
+ */
248
+ sendTeamMessage(message, callback) {
249
+ this.sendRequest({
250
+ sendTeamMessage: {
251
+ message: message,
252
+ },
253
+ }, callback);
254
+ }
255
+
256
+ /**
257
+ * Get info for an Entity
258
+ * @param entityId the id of the entity to get info of
259
+ * @param callback
260
+ */
261
+ getEntityInfo(entityId, callback) {
262
+ this.sendRequest({
263
+ entityId: entityId,
264
+ getEntityInfo: {
265
+
266
+ },
267
+ }, callback);
268
+ }
269
+
270
+ /**
271
+ * Get the Map
272
+ */
273
+ getMap(callback) {
274
+ this.sendRequest({
275
+ getMap: {
276
+
277
+ },
278
+ }, callback);
279
+ }
280
+
281
+ /**
282
+ * Get the ingame time
283
+ */
284
+ getTime(callback) {
285
+ this.sendRequest({
286
+ getTime: {
287
+
288
+ },
289
+ }, callback);
290
+ }
291
+
292
+ /**
293
+ * Get all map markers
294
+ */
295
+ getMapMarkers(callback) {
296
+ this.sendRequest({
297
+ getMapMarkers: {
298
+
299
+ },
300
+ }, callback);
301
+ }
302
+
303
+ /**
304
+ * Get the server info
305
+ */
306
+ getInfo(callback) {
307
+ this.sendRequest({
308
+ getInfo: {
309
+
310
+ },
311
+ }, callback);
312
+ }
313
+
314
+ /**
315
+ * Get team info
316
+ */
317
+ getTeamInfo(callback) {
318
+ this.sendRequest({
319
+ getTeamInfo: {
320
+
321
+ },
322
+ }, callback);
323
+ }
324
+
325
+ /**
326
+ * Subscribes to a Camera
327
+ * @param identifier Camera Identifier, such as OILRIG1 (or custom name)
328
+ * @param callback
329
+ */
330
+ subscribeToCamera(identifier, callback) {
331
+ this.sendRequest({
332
+ cameraSubscribe: {
333
+ cameraId: identifier,
334
+ },
335
+ }, callback);
336
+ }
337
+
338
+ /**
339
+ * Unsubscribes from a Camera
340
+ * @param callback
341
+ */
342
+ unsubscribeFromCamera(callback) {
343
+ this.sendRequest({
344
+ cameraUnsubscribe: {
345
+
346
+ }
347
+ }, callback)
348
+ }
349
+
350
+ /**
351
+ * Sends camera input to the server (mouse movement)
352
+ * @param buttons The buttons that are currently pressed
353
+ * @param x The x delta of the mouse movement
354
+ * @param y The y delta of the mouse movement
355
+ * @param callback
356
+ */
357
+ sendCameraInput(buttons, x, y, callback) {
358
+ this.sendRequest({
359
+ cameraInput: {
360
+ buttons: buttons,
361
+ mouseDelta: {
362
+ x: x,
363
+ y: y,
364
+ }
365
+ },
366
+ }, callback);
367
+ }
368
+
369
+ /**
370
+ * Get a camera instance for controlling CCTV Cameras, PTZ Cameras and Auto Turrets
371
+ * @param identifier Camera Identifier, such as DOME1, OILRIG1L1, (or a custom camera id)
372
+ * @returns {Camera}
373
+ */
374
+ getCamera(identifier) {
375
+ return new Camera(this, identifier);
376
+ }
377
+
378
+ }
379
+
380
+ module.exports = RustPlus;