reallink-cli 0.1.14 → 0.1.16
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 +39 -0
- package/bin/reallink.cjs +7 -2
- package/package.json +11 -4
- package/prebuilt/linux-x64/reallink-cli +0 -0
- package/rust/Cargo.lock +212 -7
- package/rust/Cargo.toml +8 -2
- package/rust/src/logs.rs +8 -3
- package/rust/src/main.rs +2241 -167
- package/rust/src/unreal.rs +225 -2
- package/scripts/postinstall.cjs +1 -1
- package/prebuilt/win32-x64/reallink-cli.exe +0 -0
package/rust/src/unreal.rs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
use anyhow::Result;
|
|
2
|
-
use clap::{ArgAction, Args, Subcommand};
|
|
2
|
+
use clap::{ArgAction, Args, Subcommand, ValueEnum};
|
|
3
3
|
use serde::{Deserialize, Serialize};
|
|
4
4
|
use std::path::PathBuf;
|
|
5
5
|
|
|
@@ -74,6 +74,15 @@ pub(crate) enum LinkCommands {
|
|
|
74
74
|
#[command(subcommand)]
|
|
75
75
|
command: LinkPluginCommands,
|
|
76
76
|
},
|
|
77
|
+
/// Register a local source folder for a project
|
|
78
|
+
Source(LinkSourceArgs),
|
|
79
|
+
/// Connect to Reallink and bridge local source to agents
|
|
80
|
+
Connect(LinkConnectArgs),
|
|
81
|
+
/// Manage P2P signaling sessions for direct CLI-to-CLI transports
|
|
82
|
+
P2p {
|
|
83
|
+
#[command(subcommand)]
|
|
84
|
+
command: LinkP2PCommands,
|
|
85
|
+
},
|
|
77
86
|
}
|
|
78
87
|
|
|
79
88
|
#[derive(Subcommand)]
|
|
@@ -82,6 +91,15 @@ pub(crate) enum LinkPluginCommands {
|
|
|
82
91
|
List(LinkPluginListArgs),
|
|
83
92
|
}
|
|
84
93
|
|
|
94
|
+
#[derive(Subcommand)]
|
|
95
|
+
pub(crate) enum LinkP2PCommands {
|
|
96
|
+
Create(LinkP2PCreateArgs),
|
|
97
|
+
List(LinkP2PListArgs),
|
|
98
|
+
Get(LinkP2PGetArgs),
|
|
99
|
+
Wait(LinkP2PWaitArgs),
|
|
100
|
+
Signal(LinkP2PSignalArgs),
|
|
101
|
+
}
|
|
102
|
+
|
|
85
103
|
#[derive(Args)]
|
|
86
104
|
pub(crate) struct LinkUnrealArgs {
|
|
87
105
|
#[arg(long, help = "Remote Reallink project id to bind")]
|
|
@@ -247,6 +265,200 @@ pub(crate) struct LinkPluginListArgs {
|
|
|
247
265
|
pub index_path: String,
|
|
248
266
|
}
|
|
249
267
|
|
|
268
|
+
// ---------------------------------------------------------------------------
|
|
269
|
+
// Source link args
|
|
270
|
+
// ---------------------------------------------------------------------------
|
|
271
|
+
|
|
272
|
+
#[derive(Args)]
|
|
273
|
+
pub(crate) struct LinkSourceArgs {
|
|
274
|
+
#[arg(long, help = "Project ID to bind the source folder to")]
|
|
275
|
+
pub project_id: String,
|
|
276
|
+
#[arg(long, help = "Local directory path containing source files")]
|
|
277
|
+
pub path: PathBuf,
|
|
278
|
+
#[arg(
|
|
279
|
+
long,
|
|
280
|
+
default_value = "project",
|
|
281
|
+
help = "Label for this folder (project, engine, etc.)"
|
|
282
|
+
)]
|
|
283
|
+
pub label: String,
|
|
284
|
+
#[arg(long)]
|
|
285
|
+
pub base_url: Option<String>,
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
#[derive(Args)]
|
|
289
|
+
pub(crate) struct LinkConnectArgs {
|
|
290
|
+
#[arg(long, help = "Project ID to connect. Uses default if omitted")]
|
|
291
|
+
pub project_id: Option<String>,
|
|
292
|
+
#[arg(
|
|
293
|
+
long,
|
|
294
|
+
help = "Stable workspace identifier for this linked client session"
|
|
295
|
+
)]
|
|
296
|
+
pub workspace_id: Option<String>,
|
|
297
|
+
#[arg(long, help = "Push file index + key source files to R2 on connect")]
|
|
298
|
+
pub sync: bool,
|
|
299
|
+
#[arg(
|
|
300
|
+
long,
|
|
301
|
+
default_value = "websocket",
|
|
302
|
+
help = "Transport used by this linked client session"
|
|
303
|
+
)]
|
|
304
|
+
pub transport: String,
|
|
305
|
+
#[arg(long, help = "Connect service URL override")]
|
|
306
|
+
pub connect_url: Option<String>,
|
|
307
|
+
#[arg(long)]
|
|
308
|
+
pub base_url: Option<String>,
|
|
309
|
+
#[arg(long, help = "Bearer token override for agent/API-token usage")]
|
|
310
|
+
pub access_token: Option<String>,
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
#[derive(Clone, Debug, ValueEnum)]
|
|
314
|
+
pub(crate) enum LinkP2PRole {
|
|
315
|
+
Agent,
|
|
316
|
+
Client,
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
impl LinkP2PRole {
|
|
320
|
+
pub(crate) fn as_api_str(&self) -> &'static str {
|
|
321
|
+
match self {
|
|
322
|
+
Self::Agent => "agent",
|
|
323
|
+
Self::Client => "client",
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
#[derive(Clone, Debug, ValueEnum)]
|
|
329
|
+
pub(crate) enum LinkP2PSignalType {
|
|
330
|
+
Offer,
|
|
331
|
+
Answer,
|
|
332
|
+
Candidate,
|
|
333
|
+
Ready,
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
impl LinkP2PSignalType {
|
|
337
|
+
pub(crate) fn as_api_str(&self) -> &'static str {
|
|
338
|
+
match self {
|
|
339
|
+
Self::Offer => "offer",
|
|
340
|
+
Self::Answer => "answer",
|
|
341
|
+
Self::Candidate => "candidate",
|
|
342
|
+
Self::Ready => "ready",
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
#[derive(Args)]
|
|
348
|
+
pub(crate) struct LinkP2PCreateArgs {
|
|
349
|
+
#[arg(long, help = "Project ID to attach the P2P session to")]
|
|
350
|
+
pub project_id: String,
|
|
351
|
+
#[arg(long, help = "Stable workspace identifier for this P2P session")]
|
|
352
|
+
pub workspace_id: Option<String>,
|
|
353
|
+
#[arg(
|
|
354
|
+
long,
|
|
355
|
+
help = "Optional source clientId already registered under the workspace"
|
|
356
|
+
)]
|
|
357
|
+
pub client_id: Option<String>,
|
|
358
|
+
#[arg(long, help = "Optional peer clientId expected to join this session")]
|
|
359
|
+
pub peer_client_id: Option<String>,
|
|
360
|
+
#[arg(long, help = "Session TTL in seconds")]
|
|
361
|
+
pub ttl_seconds: Option<u64>,
|
|
362
|
+
#[arg(
|
|
363
|
+
long,
|
|
364
|
+
help = "Inline JSON object or @path/to/file.json with additional metadata"
|
|
365
|
+
)]
|
|
366
|
+
pub metadata: Option<String>,
|
|
367
|
+
#[arg(long)]
|
|
368
|
+
pub base_url: Option<String>,
|
|
369
|
+
#[arg(long, help = "Bearer token override for agent/API-token usage")]
|
|
370
|
+
pub access_token: Option<String>,
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
#[derive(Args)]
|
|
374
|
+
pub(crate) struct LinkP2PGetArgs {
|
|
375
|
+
#[arg(long, help = "Project ID owning the P2P session")]
|
|
376
|
+
pub project_id: String,
|
|
377
|
+
#[arg(long, help = "P2P session identifier")]
|
|
378
|
+
pub session_id: String,
|
|
379
|
+
#[arg(long)]
|
|
380
|
+
pub base_url: Option<String>,
|
|
381
|
+
#[arg(long, help = "Bearer token override for agent/API-token usage")]
|
|
382
|
+
pub access_token: Option<String>,
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
#[derive(Args)]
|
|
386
|
+
pub(crate) struct LinkP2PListArgs {
|
|
387
|
+
#[arg(long, help = "Project ID owning the P2P sessions")]
|
|
388
|
+
pub project_id: String,
|
|
389
|
+
#[arg(long)]
|
|
390
|
+
pub workspace_id: Option<String>,
|
|
391
|
+
#[arg(long)]
|
|
392
|
+
pub client_id: Option<String>,
|
|
393
|
+
#[arg(long)]
|
|
394
|
+
pub status: Option<String>,
|
|
395
|
+
#[arg(long, default_value_t = 50)]
|
|
396
|
+
pub limit: u32,
|
|
397
|
+
#[arg(long)]
|
|
398
|
+
pub base_url: Option<String>,
|
|
399
|
+
#[arg(long, help = "Bearer token override for agent/API-token usage")]
|
|
400
|
+
pub access_token: Option<String>,
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
#[derive(Args)]
|
|
404
|
+
pub(crate) struct LinkP2PWaitArgs {
|
|
405
|
+
#[arg(long, help = "Project ID owning the P2P session")]
|
|
406
|
+
pub project_id: String,
|
|
407
|
+
#[arg(long, help = "P2P session identifier")]
|
|
408
|
+
pub session_id: String,
|
|
409
|
+
#[arg(long, default_value = "ready")]
|
|
410
|
+
pub status: String,
|
|
411
|
+
#[arg(long, default_value_t = 30_000)]
|
|
412
|
+
pub timeout_ms: u64,
|
|
413
|
+
#[arg(long, default_value_t = 1_000)]
|
|
414
|
+
pub poll_interval_ms: u64,
|
|
415
|
+
#[arg(long)]
|
|
416
|
+
pub base_url: Option<String>,
|
|
417
|
+
#[arg(long, help = "Bearer token override for agent/API-token usage")]
|
|
418
|
+
pub access_token: Option<String>,
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
#[derive(Args)]
|
|
422
|
+
pub(crate) struct LinkP2PSignalArgs {
|
|
423
|
+
#[arg(long, help = "Project ID owning the P2P session")]
|
|
424
|
+
pub project_id: String,
|
|
425
|
+
#[arg(long, help = "P2P session identifier")]
|
|
426
|
+
pub session_id: String,
|
|
427
|
+
#[arg(long, value_enum)]
|
|
428
|
+
pub role: LinkP2PRole,
|
|
429
|
+
#[arg(long = "signal-type", value_enum)]
|
|
430
|
+
pub signal_type: LinkP2PSignalType,
|
|
431
|
+
#[arg(
|
|
432
|
+
long,
|
|
433
|
+
help = "Inline JSON object or @path/to/file.json carrying the signal payload"
|
|
434
|
+
)]
|
|
435
|
+
pub payload: String,
|
|
436
|
+
#[arg(long, help = "Idempotency key for this signal")]
|
|
437
|
+
pub signal_id: Option<String>,
|
|
438
|
+
#[arg(long, help = "Optional registered clientId originating this signal")]
|
|
439
|
+
pub from_client_id: Option<String>,
|
|
440
|
+
#[arg(long)]
|
|
441
|
+
pub base_url: Option<String>,
|
|
442
|
+
#[arg(long, help = "Bearer token override for agent/API-token usage")]
|
|
443
|
+
pub access_token: Option<String>,
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
447
|
+
#[serde(rename_all = "camelCase")]
|
|
448
|
+
pub(crate) struct SourceLinkRecord {
|
|
449
|
+
pub project_id: String,
|
|
450
|
+
pub folder_path: String,
|
|
451
|
+
pub folder_label: String,
|
|
452
|
+
pub created_at_epoch_ms: u128,
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
|
|
456
|
+
#[serde(rename_all = "camelCase")]
|
|
457
|
+
pub(crate) struct SourceLinksConfig {
|
|
458
|
+
pub version: u32,
|
|
459
|
+
pub links: Vec<SourceLinkRecord>,
|
|
460
|
+
}
|
|
461
|
+
|
|
250
462
|
pub(crate) async fn dispatch(client: &reqwest::Client, command: LinkCommands) -> Result<()> {
|
|
251
463
|
match command {
|
|
252
464
|
LinkCommands::Unreal(args) => crate::link_unreal_command(client, args).await?,
|
|
@@ -258,9 +470,20 @@ pub(crate) async fn dispatch(client: &reqwest::Client, command: LinkCommands) ->
|
|
|
258
470
|
LinkCommands::Open(args) => crate::link_open_command(args).await?,
|
|
259
471
|
LinkCommands::Run(args) => crate::link_run_command(args).await?,
|
|
260
472
|
LinkCommands::Plugin { command } => match command {
|
|
261
|
-
LinkPluginCommands::Install(args) =>
|
|
473
|
+
LinkPluginCommands::Install(args) => {
|
|
474
|
+
crate::link_plugin_install_command(client, args).await?
|
|
475
|
+
}
|
|
262
476
|
LinkPluginCommands::List(args) => crate::link_plugin_list_command(client, args).await?,
|
|
263
477
|
},
|
|
478
|
+
LinkCommands::Source(args) => crate::link_source_command(client, args).await?,
|
|
479
|
+
LinkCommands::Connect(args) => crate::link_connect_command(client, args).await?,
|
|
480
|
+
LinkCommands::P2p { command } => match command {
|
|
481
|
+
LinkP2PCommands::Create(args) => crate::link_p2p_create_command(client, args).await?,
|
|
482
|
+
LinkP2PCommands::List(args) => crate::link_p2p_list_command(client, args).await?,
|
|
483
|
+
LinkP2PCommands::Get(args) => crate::link_p2p_get_command(client, args).await?,
|
|
484
|
+
LinkP2PCommands::Wait(args) => crate::link_p2p_wait_command(client, args).await?,
|
|
485
|
+
LinkP2PCommands::Signal(args) => crate::link_p2p_signal_command(client, args).await?,
|
|
486
|
+
},
|
|
264
487
|
}
|
|
265
488
|
Ok(())
|
|
266
489
|
}
|
package/scripts/postinstall.cjs
CHANGED
|
@@ -25,7 +25,7 @@ if (process.env.REALLINK_SKIP_BUILD === "1") {
|
|
|
25
25
|
process.exit(0);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
if (hasReleaseBinary() || fs.existsSync(prebuiltBinaryPath)) {
|
|
28
|
+
if (process.env.REALLINK_FORCE_BUILD !== "1" && (hasReleaseBinary() || fs.existsSync(prebuiltBinaryPath))) {
|
|
29
29
|
process.exit(0);
|
|
30
30
|
}
|
|
31
31
|
|
|
Binary file
|