66use async_trait:: async_trait;
77use dialoguer:: { theme:: ColorfulTheme , Input , Password } ;
88use lazy_static:: lazy_static;
9- use std:: { ffi:: OsString , sync:: Mutex , thread, time:: Duration } ;
9+ use std:: { ffi:: OsString , path :: PathBuf , sync:: Mutex , thread, time:: Duration } ;
1010use tokio:: sync:: mpsc;
1111use windows_service:: {
1212 define_windows_service,
@@ -21,27 +21,31 @@ use windows_service::{
2121
2222use crate :: {
2323 commands:: tunnels:: ShutdownSignal ,
24- util:: errors:: { wrap, AnyError , WindowsNeedsElevation } ,
24+ util:: errors:: { wrap, wrapdbg , AnyError , WindowsNeedsElevation } ,
2525} ;
2626use crate :: {
2727 log:: { self , FileLogSink } ,
2828 state:: LauncherPaths ,
2929} ;
3030
3131use super :: service:: {
32- ServiceContainer , ServiceManager as CliServiceManager , SERVICE_LOG_FILE_NAME ,
32+ tail_log_file , ServiceContainer , ServiceManager as CliServiceManager , SERVICE_LOG_FILE_NAME ,
3333} ;
3434
3535pub struct WindowsService {
3636 log : log:: Logger ,
37+ log_file : PathBuf ,
3738}
3839
3940const SERVICE_NAME : & str = "code_tunnel" ;
4041const SERVICE_TYPE : ServiceType = ServiceType :: OWN_PROCESS ;
4142
4243impl WindowsService {
43- pub fn new ( log : log:: Logger ) -> Self {
44- Self { log }
44+ pub fn new ( log : log:: Logger , paths : & LauncherPaths ) -> Self {
45+ Self {
46+ log,
47+ log_file : paths. service_log_file ( ) ,
48+ }
4549 }
4650}
4751
@@ -54,14 +58,18 @@ impl CliServiceManager for WindowsService {
5458 )
5559 . map_err ( |e| WindowsNeedsElevation ( format ! ( "error getting service manager: {}" , e) ) ) ?;
5660
61+ let mut args = args. iter ( ) . map ( OsString :: from) . collect :: < Vec < OsString > > ( ) ;
62+ args. push ( OsString :: from ( "--log-to-file" ) ) ;
63+ args. push ( self . log_file . as_os_str ( ) . to_os_string ( ) ) ;
64+
5765 let mut service_info = ServiceInfo {
5866 name : OsString :: from ( SERVICE_NAME ) ,
5967 display_name : OsString :: from ( "VS Code Tunnel" ) ,
6068 service_type : SERVICE_TYPE ,
6169 start_type : ServiceStartType :: AutoStart ,
6270 error_control : ServiceErrorControl :: Normal ,
6371 executable_path : exe,
64- launch_arguments : args. iter ( ) . map ( OsString :: from ) . collect ( ) ,
72+ launch_arguments : args,
6573 dependencies : vec ! [ ] ,
6674 account_name : None ,
6775 account_password : None ,
@@ -74,7 +82,7 @@ impl CliServiceManager for WindowsService {
7482 let service = if let Ok ( service) = existing_service {
7583 service
7684 . change_config ( & service_info)
77- . map_err ( |e| wrap ( e, "error updating existing service" ) ) ?;
85+ . map_err ( |e| wrapdbg ( e, "error updating existing service" ) ) ?;
7886 service
7987 } else {
8088 loop {
@@ -112,15 +120,15 @@ impl CliServiceManager for WindowsService {
112120 if status == ServiceState :: Stopped {
113121 service
114122 . start :: < & str > ( & [ ] )
115- . map_err ( |e| wrap ( e, "error starting service" ) ) ?;
123+ . map_err ( |e| wrapdbg ( e, "error starting service" ) ) ?;
116124 }
117125
118126 info ! ( self . log, "Tunnel service successfully started" ) ;
119127 Ok ( ( ) )
120128 }
121129
122130 async fn show_logs ( & self ) -> Result < ( ) , AnyError > {
123- todo ! ( ) ;
131+ tail_log_file ( & self . log_file ) . await
124132 }
125133
126134 #[ allow( unused_must_use) ] // triggers incorrectly on `define_windows_service!`
@@ -136,7 +144,7 @@ impl CliServiceManager for WindowsService {
136144 Ok ( sink) => self . log . tee ( sink) ,
137145 Err ( e) => {
138146 warning ! ( self . log, "Failed to create service log file: {}" , e) ;
139- self . log . clone ( )
147+ self . log
140148 }
141149 } ;
142150
@@ -176,12 +184,12 @@ impl CliServiceManager for WindowsService {
176184
177185 let service_status = service
178186 . query_status ( )
179- . map_err ( |e| wrap ( e, "error getting service status" ) ) ?;
187+ . map_err ( |e| wrapdbg ( e, "error getting service status" ) ) ?;
180188
181189 if service_status. current_state != ServiceState :: Stopped {
182190 service
183191 . stop ( )
184- . map_err ( |e| wrap ( e, "error getting stopping service" ) ) ?;
192+ . map_err ( |e| wrapdbg ( e, "error getting stopping service" ) ) ?;
185193
186194 while let Ok ( ServiceState :: Stopped ) = service. query_status ( ) . map ( |s| s. current_state ) {
187195 info ! ( self . log, "Polling for service to stop..." ) ;
@@ -191,7 +199,7 @@ impl CliServiceManager for WindowsService {
191199
192200 service
193201 . delete ( )
194- . map_err ( |e| wrap ( e, "error deleting service" ) ) ?;
202+ . map_err ( |e| wrapdbg ( e, "error deleting service" ) ) ?;
195203
196204 Ok ( ( ) )
197205 }
@@ -212,7 +220,7 @@ fn service_main(_arguments: Vec<OsString>) -> Result<(), AnyError> {
212220 let mut service = SERVICE_IMPL . lock ( ) . unwrap ( ) . take ( ) . unwrap ( ) ;
213221
214222 // Create a channel to be able to poll a stop event from the service worker loop.
215- let ( shutdown_tx, shutdown_rx) = mpsc:: channel :: < ShutdownSignal > ( 5 ) ;
223+ let ( shutdown_tx, shutdown_rx) = mpsc:: unbounded_channel :: < ShutdownSignal > ( ) ;
216224 let mut shutdown_tx = Some ( shutdown_tx) ;
217225
218226 // Define system service event handler that will be receiving service events.
@@ -222,7 +230,7 @@ fn service_main(_arguments: Vec<OsString>) -> Result<(), AnyError> {
222230 ServiceControl :: Stop => {
223231 shutdown_tx
224232 . take ( )
225- . and_then ( |tx| tx. blocking_send ( ShutdownSignal :: ServiceStopped ) . ok ( ) ) ;
233+ . and_then ( |tx| tx. send ( ShutdownSignal :: ServiceStopped ) . ok ( ) ) ;
226234 ServiceControlHandlerResult :: NoError
227235 }
228236 _ => ServiceControlHandlerResult :: NotImplemented ,
@@ -245,6 +253,13 @@ fn service_main(_arguments: Vec<OsString>) -> Result<(), AnyError> {
245253 } )
246254 . map_err ( |e| wrap ( e, "error marking service as running" ) ) ?;
247255
256+ info ! ( service. log, "Starting service loop..." ) ;
257+
258+ let panic_log = service. log . clone ( ) ;
259+ std:: panic:: set_hook ( Box :: new ( move |p| {
260+ error ! ( panic_log, "Service panic: {:?}" , p) ;
261+ } ) ) ;
262+
248263 let result = tokio:: runtime:: Builder :: new_multi_thread ( )
249264 . enable_all ( )
250265 . build ( )
0 commit comments