@@ -11,6 +11,7 @@ use dsc_lib::{
1111 } ,
1212 DscManager ,
1313} ;
14+ use rust_i18n:: { i18n, t} ;
1415use std:: { env, io, process} ;
1516use tonic:: { transport:: Server , Request , Response , Status } ;
1617
@@ -26,6 +27,8 @@ use proto::{
2627 TypeFilesResponse ,
2728} ;
2829
30+ i18n ! ( "locales" , fallback = "en-us" ) ;
31+
2932#[ derive( Debug , Default ) ]
3033pub struct BicepExtensionService ;
3134
@@ -40,18 +43,38 @@ impl BicepExtension for BicepExtensionService {
4043 let version = spec. api_version ;
4144 let properties = spec. properties ;
4245
43- tracing:: debug!( "CreateOrUpdate called for {resource_type}@{version:?}: {properties}" ) ;
46+ tracing:: debug!(
47+ "{}" ,
48+ t!(
49+ "dscbicep.functionCalled" ,
50+ function = "CreateOrUpdate" ,
51+ resourceType = resource_type,
52+ version = format!( "{version:?}" ) ,
53+ properties = properties
54+ )
55+ ) ;
4456
4557 let mut dsc = DscManager :: new ( ) ;
46- let Some ( resource) = dsc. find_resource ( & DiscoveryFilter :: new ( & resource_type, version. as_deref ( ) , None ) ) . unwrap_or ( None ) else {
47- return Err ( Status :: not_found ( "Resource not found" ) ) ;
58+ let Some ( resource) = dsc
59+ . find_resource ( & DiscoveryFilter :: new (
60+ & resource_type,
61+ version. as_deref ( ) ,
62+ None ,
63+ ) )
64+ . unwrap_or ( None )
65+ else {
66+ return Err ( Status :: not_found (
67+ t ! ( "dscerror.resourceNotFound" ) . to_string ( ) ,
68+ ) ) ;
4869 } ;
4970
5071 let SetResult :: Resource ( result) = resource
5172 . set ( & properties, false , & ExecutionKind :: Actual )
5273 . map_err ( |e| Status :: aborted ( e. to_string ( ) ) ) ?
5374 else {
54- return Err ( Status :: unimplemented ( "Group resources not supported" ) ) ;
75+ return Err ( Status :: unimplemented (
76+ t ! ( "dscerror.notSupported" ) . to_string ( ) ,
77+ ) ) ;
5578 } ;
5679
5780 Ok ( Response :: new ( LocalExtensibilityOperationResponse {
@@ -75,18 +98,38 @@ impl BicepExtension for BicepExtensionService {
7598 let version = spec. api_version ;
7699 let properties = spec. properties ;
77100
78- tracing:: debug!( "Preview called for {resource_type}@{version:?}: {properties}" ) ;
101+ tracing:: debug!(
102+ "{}" ,
103+ t!(
104+ "dscbicep.functionCalled" ,
105+ function = "Preview" ,
106+ resourceType = resource_type,
107+ version = format!( "{version:?}" ) ,
108+ properties = properties
109+ )
110+ ) ;
79111
80112 let mut dsc = DscManager :: new ( ) ;
81- let Some ( resource) = dsc. find_resource ( & DiscoveryFilter :: new ( & resource_type, version. as_deref ( ) , None ) ) . unwrap_or ( None ) else {
82- return Err ( Status :: not_found ( "Resource not found" ) ) ;
113+ let Some ( resource) = dsc
114+ . find_resource ( & DiscoveryFilter :: new (
115+ & resource_type,
116+ version. as_deref ( ) ,
117+ None ,
118+ ) )
119+ . unwrap_or ( None )
120+ else {
121+ return Err ( Status :: not_found (
122+ t ! ( "dscerror.resourceNotFound" ) . to_string ( ) ,
123+ ) ) ;
83124 } ;
84125
85126 let SetResult :: Resource ( result) = resource
86127 . set ( & properties, false , & ExecutionKind :: WhatIf )
87128 . map_err ( |e| Status :: aborted ( e. to_string ( ) ) ) ?
88129 else {
89- return Err ( Status :: unimplemented ( "Group resources not supported" ) ) ;
130+ return Err ( Status :: unimplemented (
131+ t ! ( "dscerror.notSupported" ) . to_string ( ) ,
132+ ) ) ;
90133 } ;
91134
92135 Ok ( Response :: new ( LocalExtensibilityOperationResponse {
@@ -110,18 +153,38 @@ impl BicepExtension for BicepExtensionService {
110153 let version = reference. api_version . clone ( ) ;
111154 let identifiers = reference. identifiers . clone ( ) ;
112155
113- tracing:: debug!( "Get called for {resource_type}@{version:?}: {identifiers}" ) ;
156+ tracing:: debug!(
157+ "{}" ,
158+ t!(
159+ "dscbicep.functionCalled" ,
160+ function = "Get" ,
161+ resourceType = resource_type,
162+ version = format!( "{version:?}" ) ,
163+ properties = identifiers
164+ )
165+ ) ;
114166
115167 let mut dsc = DscManager :: new ( ) ;
116- let Some ( resource) = dsc. find_resource ( & DiscoveryFilter :: new ( & resource_type, version. as_deref ( ) , None ) ) . unwrap_or ( None ) else {
117- return Err ( Status :: not_found ( "Resource not found" ) ) ;
168+ let Some ( resource) = dsc
169+ . find_resource ( & DiscoveryFilter :: new (
170+ & resource_type,
171+ version. as_deref ( ) ,
172+ None ,
173+ ) )
174+ . unwrap_or ( None )
175+ else {
176+ return Err ( Status :: not_found (
177+ t ! ( "dscerror.resourceNotFound" ) . to_string ( ) ,
178+ ) ) ;
118179 } ;
119180
120181 let GetResult :: Resource ( result) = resource
121182 . get ( & identifiers)
122183 . map_err ( |e| Status :: aborted ( e. to_string ( ) ) ) ?
123184 else {
124- return Err ( Status :: unimplemented ( "Group resources not supported" ) ) ;
185+ return Err ( Status :: unimplemented (
186+ t ! ( "dscerror.notSupported" ) . to_string ( ) ,
187+ ) ) ;
125188 } ;
126189
127190 Ok ( Response :: new ( LocalExtensibilityOperationResponse {
@@ -146,15 +209,28 @@ impl BicepExtension for BicepExtensionService {
146209 let identifiers = reference. identifiers . clone ( ) ;
147210
148211 tracing:: debug!(
149- "Delete called for {}@{:?}: {}" ,
150- resource_type,
151- version,
152- identifiers
212+ "{}" ,
213+ t!(
214+ "dscbicep.functionCalled" ,
215+ function = "Delete" ,
216+ resourceType = resource_type,
217+ version = format!( "{version:?}" ) ,
218+ properties = identifiers
219+ )
153220 ) ;
154221
155222 let mut dsc = DscManager :: new ( ) ;
156- let Some ( resource) = dsc. find_resource ( & DiscoveryFilter :: new ( & resource_type, version. as_deref ( ) , None ) ) . unwrap_or ( None ) else {
157- return Err ( Status :: not_found ( "Resource not found" ) ) ;
223+ let Some ( resource) = dsc
224+ . find_resource ( & DiscoveryFilter :: new (
225+ & resource_type,
226+ version. as_deref ( ) ,
227+ None ,
228+ ) )
229+ . unwrap_or ( None )
230+ else {
231+ return Err ( Status :: not_found (
232+ t ! ( "dscerror.resourceNotFound" ) . to_string ( ) ,
233+ ) ) ;
158234 } ;
159235
160236 resource
@@ -177,15 +253,13 @@ impl BicepExtension for BicepExtensionService {
177253 & self ,
178254 _request : Request < Empty > ,
179255 ) -> Result < Response < TypeFilesResponse > , Status > {
180- tracing:: debug!( "GetTypeFiles called" ) ;
181-
182- // TODO: Return actual Bicep type definitions...yet the extension already has these?
183- // Perhaps this is where we can dynamically get them from the current system.
184- Err ( Status :: unimplemented ( "GetTypeFiles not yet implemented" ) )
256+ // TODO: Dynamically return type definitions for DSC resources found on the system.
257+ Err ( Status :: unimplemented (
258+ t ! ( "dscerror.notImplemented" ) . to_string ( ) ,
259+ ) )
185260 }
186261
187262 async fn ping ( & self , _request : Request < Empty > ) -> Result < Response < Empty > , Status > {
188- tracing:: debug!( "Ping called" ) ;
189263 Ok ( Response :: new ( Empty { } ) )
190264 }
191265}
@@ -224,7 +298,14 @@ async fn run_server(
224298 use tokio:: net:: UnixListener ;
225299 use tokio_stream:: wrappers:: UnixListenerStream ;
226300
227- tracing:: info!( "Starting Bicep gRPC server on Unix socket: {socket_path}" ) ;
301+ tracing:: info!(
302+ "{}" ,
303+ t!(
304+ "dscbicep.starting" ,
305+ transport = "socket" ,
306+ address = socket_path
307+ )
308+ ) ;
228309
229310 // Remove the socket file if it exists
230311 let _ = std:: fs:: remove_file ( & socket_path) ;
@@ -298,7 +379,14 @@ async fn run_server(
298379
299380 // Windows named pipes must be in the format \\.\pipe\{name}
300381 let full_pipe_path = format ! ( r"\\.\pipe\{}" , pipe_name) ;
301- tracing:: info!( "Starting Bicep gRPC server on named pipe: {full_pipe_path}" ) ;
382+ tracing:: info!(
383+ "{}" ,
384+ t!(
385+ "dscbicep.starting" ,
386+ transport = "named pipe" ,
387+ address = full_pipe_path
388+ )
389+ ) ;
302390
303391 // Create a stream that accepts connections on the named pipe
304392 let incoming = async_stream:: stream! {
@@ -318,21 +406,19 @@ async fn run_server(
318406 let server = match pipe {
319407 Ok ( server) => server,
320408 Err ( e) => {
321- tracing:: error!( "Failed to create named pipe: {}" , e ) ;
409+ tracing:: error!( "{}" , t! ( "dscbicep.serverError" , error = e . to_string ( ) ) ) ;
322410 break ;
323411 }
324412 } ;
325413
326414 is_first = false ;
327415
328- tracing:: debug!( "Waiting for client to connect to named pipe..." ) ;
329416 match server. connect( ) . await {
330417 Ok ( ( ) ) => {
331- tracing:: info!( "Client connected to named pipe" ) ;
332418 yield Ok :: <_, std:: io:: Error >( NamedPipeConnection ( server) ) ;
333419 }
334420 Err ( e) => {
335- tracing:: error!( "Failed to accept connection: {}" , e ) ;
421+ tracing:: error!( "{}" , t! ( "dscbicep.serverError" , error = e . to_string ( ) ) ) ;
336422 break ;
337423 }
338424 }
@@ -348,8 +434,15 @@ async fn run_server(
348434 }
349435
350436 // Default to HTTP server on [::1]:50051 if no transport specified
351- let addr = http. unwrap_or_else ( || "[::1]:50051" . to_string ( ) ) . parse ( ) ?;
352- tracing:: info!( "Starting Bicep gRPC server on HTTP: {addr}" ) ;
437+ let addr = http. unwrap_or_else ( || "[::1]:50051" . to_string ( ) ) ;
438+ tracing:: info!(
439+ "{}" ,
440+ t!(
441+ "dscbicep.starting" ,
442+ transport = "HTTP" ,
443+ address = addr. to_string( )
444+ )
445+ ) ;
353446
354447 let reflection_service = tonic_reflection:: server:: Builder :: configure ( )
355448 . register_encoded_file_descriptor_set ( proto:: FILE_DESCRIPTOR_SET )
@@ -359,7 +452,7 @@ async fn run_server(
359452 Server :: builder ( )
360453 . add_service ( reflection_service)
361454 . add_service ( BicepExtensionServer :: new ( service) )
362- . serve ( addr)
455+ . serve ( addr. parse ( ) ? )
363456 . await ?;
364457
365458 Ok ( ( ) )
@@ -386,36 +479,28 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
386479 . init ( ) ;
387480
388481 let args = Args :: parse ( ) ;
389- tracing:: debug!( "Args are {args:#?}" ) ;
390482
391483 if args. wait_for_debugger
392484 || env:: var_os ( "DSC_GRPC_DEBUG" ) . is_some_and ( |v| v. eq_ignore_ascii_case ( "true" ) )
393485 {
394- tracing:: warn!(
395- "Press any key to continue after attaching to PID: {}" ,
396- process:: id( )
397- ) ;
486+ tracing:: warn!( "{}" , t!( "dscbicep.waitForDebugger" , pid = process:: id( ) ) ) ;
398487 let mut input = String :: new ( ) ;
399488 io:: stdin ( ) . read_line ( & mut input) ?;
400489 }
401490
402491 // Set up graceful shutdown on SIGTERM/SIGINT
403492 let shutdown_signal = async {
404- tokio:: signal:: ctrl_c ( )
405- . await
406- . expect ( "Failed to listen for shutdown signal" ) ;
407- tracing:: info!( "Received shutdown signal, terminating gracefully..." ) ;
493+ tokio:: signal:: ctrl_c ( ) . await . unwrap ( ) ;
408494 } ;
409495
410496 tokio:: select! {
411497 result = run_server( args. socket, args. pipe, args. http) => {
412498 if let Err ( e) = result {
413- tracing:: error!( "Server error: {e}" ) ;
499+ tracing:: error!( "{}" , t! ( "dscbicep.serverError" , error = e . to_string ( ) ) ) ;
414500 return Err ( e) ;
415501 }
416502 }
417503 _ = shutdown_signal => {
418- tracing:: info!( "Shutdown complete" ) ;
419504 }
420505 }
421506
0 commit comments