1- use std:: sync:: Arc ;
1+ use std:: { sync:: Arc , time :: Duration } ;
22
3- use tokio:: net:: { TcpListener , TcpStream } ;
3+ use tokio:: {
4+ net:: { TcpListener , TcpStream } ,
5+ time:: timeout,
6+ } ;
47use tokio_util:: sync:: CancellationToken ;
5- use tracing:: { debug, error, info, warn } ;
8+ use tracing:: { debug, error, info} ;
69use url:: Url ;
710use wsrx:: proxy;
811
@@ -13,55 +16,75 @@ pub async fn launch(
1316) {
1417 let log_json = log_json. unwrap_or ( false ) ;
1518 init_logger ( log_json) ;
16- let port = port. unwrap_or ( 0 ) ;
17- let host = host. unwrap_or ( String :: from ( "127.0.0.1" ) ) ;
18- let listener = TcpListener :: bind ( format ! ( "{host}:{port}" ) )
19- . await
20- . expect ( "failed to bind port" ) ;
21- let Ok ( url) = Url :: parse ( & address) else {
22- error ! ( "Invalid url, please check your input." ) ;
19+ let Ok ( parsed_url) = Url :: parse ( & address) else {
20+ eprintln ! ( "连接地址无效,请粘贴题目页提供的完整 ws:// 或 wss:// 地址。" ) ;
2321 return ;
2422 } ;
25- if url . scheme ( ) != "ws" && url . scheme ( ) != "wss" {
26- error ! ( "Invalid url scheme, only `ws` and ` wss` are supported. " ) ;
23+ if parsed_url . scheme ( ) != "ws" && parsed_url . scheme ( ) != "wss" {
24+ eprintln ! ( "连接地址协议无效,只支持 ws:// 或 wss://。 " ) ;
2725 return ;
2826 }
29- let url = url. as_ref ( ) . to_string ( ) ;
30- info ! (
31- "Hi, I am not RX, RX is here -> {}" ,
32- listener. local_addr( ) . unwrap( )
33- ) ;
34- warn ! (
35- "wsrx will not report non-critical errors by default, you can set `RUST_LOG=wsrx=debug` to see more details."
36- ) ;
27+
28+ let port = port. unwrap_or ( 0 ) ;
29+ let host = host. unwrap_or ( String :: from ( "127.0.0.1" ) ) ;
30+ let listener = match TcpListener :: bind ( format ! ( "{host}:{port}" ) ) . await {
31+ Ok ( listener) => listener,
32+ Err ( err) => {
33+ eprintln ! ( "无法创建本地监听地址 {host}:{port}:{err}" ) ;
34+ return ;
35+ }
36+ } ;
37+ let local_addr = listener
38+ . local_addr ( )
39+ . expect ( "failed to read local listener address" ) ;
40+ let url = parsed_url. as_ref ( ) . to_string ( ) ;
41+
42+ println ! ( "LabStreamGate CLI 已启动" ) ;
43+ println ! ( "本地连接地址:{local_addr}" ) ;
44+ println ! ( "远端通道:{url}" ) ;
45+ println ! ( "请保持此进程运行,并让浏览器、nc、SSH 或调试器连接上面的本地地址。" ) ;
46+ println ! ( "无需使用 sudo;按 Ctrl+C 退出。\n " ) ;
47+ info ! ( local = %local_addr, remote = %url, "local tunnel listener started" ) ;
3748
3849 let token = CancellationToken :: new ( ) ;
3950 let url = Arc :: new ( url) ;
4051
41- // This loop will "run forever"
4252 loop {
43- let Ok ( ( tcp, _) ) = listener. accept ( ) . await else {
44- error ! ( "Failed to accept tcp connection, exiting." ) ;
45- token. cancel ( ) ;
46- return ;
53+ let accepted = tokio:: select! {
54+ result = listener. accept( ) => result,
55+ result = tokio:: signal:: ctrl_c( ) => {
56+ if let Err ( err) = result {
57+ error!( "failed to listen for Ctrl+C: {err}" ) ;
58+ }
59+ println!( "\n LabStreamGate CLI 已退出。" ) ;
60+ token. cancel( ) ;
61+ return ;
62+ }
63+ } ;
64+ let ( tcp, peer_addr) = match accepted {
65+ Ok ( connection) => connection,
66+ Err ( err) => {
67+ eprintln ! ( "本地监听失败,LabStreamGate CLI 已退出:{err}" ) ;
68+ token. cancel ( ) ;
69+ return ;
70+ }
4771 } ;
4872
4973 if token. is_cancelled ( ) {
5074 return ;
5175 }
5276
5377 let url = url. clone ( ) ;
54- let peer_addr = tcp. peer_addr ( ) . unwrap ( ) ;
55-
56- info ! ( "CREATE remote <-wsrx-> {}" , peer_addr) ;
78+ println ! ( "收到本地连接 {peer_addr},正在连接远端通道……" ) ;
79+ info ! ( remote = %url, peer = %peer_addr, "opening remote tunnel connection" ) ;
5780
5881 let token = token. clone ( ) ;
5982 tokio:: spawn ( async move {
6083 match proxy_ws_addr ( url. as_ref ( ) , tcp, token) . await {
61- Ok ( _) => { }
84+ Ok ( _) => println ! ( "本地连接 {peer_addr} 已关闭。" ) ,
6285 Err ( e) => {
63- info ! ( "REMOVE remote <-wsrx-> {} with error" , peer_addr ) ;
64- debug ! ( "TCP connection closed: {}" , e ) ;
86+ eprintln ! ( "连接远端通道失败(本地连接 {peer_addr}):{e}" ) ;
87+ debug ! ( peer = %peer_addr , error = %e , "TCP connection closed with error" ) ;
6588 }
6689 }
6790 } ) ;
@@ -72,8 +95,15 @@ async fn proxy_ws_addr(
7295 addr : impl AsRef < str > , tcp : TcpStream , token : CancellationToken ,
7396) -> Result < ( ) , wsrx:: Error > {
7497 let peer_addr = tcp. peer_addr ( ) . unwrap ( ) ;
75- let ( ws, _) = tokio_tungstenite:: connect_async ( addr. as_ref ( ) ) . await ?;
98+ let ( ws, _) = timeout (
99+ Duration :: from_secs ( 15 ) ,
100+ tokio_tungstenite:: connect_async ( addr. as_ref ( ) ) ,
101+ )
102+ . await
103+ . map_err ( |_| {
104+ std:: io:: Error :: new ( std:: io:: ErrorKind :: TimedOut , "连接远端通道超时(15 秒)" )
105+ } ) ??;
76106 proxy ( ws. into ( ) , tcp, token) . await ?;
77- info ! ( "REMOVE remote <-wsrx-> {}" , peer_addr ) ;
107+ info ! ( peer = %peer_addr , "remote tunnel connection closed" ) ;
78108 Ok ( ( ) )
79109}
0 commit comments