@@ -86,13 +86,150 @@ const Speed: React.FC<SpeedComponentProperties> = ({upload, data}) => upload ? (
8686 </ >
8787) : ( < DownloadSpeed { ...data } /> ) ;
8888
89+ type VerboseInfoProperties = {
90+ readonly data : PartialSpeedData ;
91+ readonly singleLine ?: boolean ;
92+ } ;
93+
94+ const VerboseInfo : React . FC < VerboseInfoProperties > = ( { data, singleLine} ) => {
95+ const hasLatencyData = data . latency !== undefined || data . bufferBloat !== undefined ;
96+ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
97+ const hasClientData = Boolean ( data . userLocation || data . userIp ) ;
98+
99+ return (
100+ < >
101+ { ! singleLine && < Newline /> }
102+ < Box flexDirection = 'column' >
103+ < Box >
104+ < Text > < FixedSpacer size = { 4 } /> </ Text >
105+ < Text dimColor > Latency: </ Text >
106+ { hasLatencyData ? (
107+ < >
108+ { data . latency !== undefined && (
109+ < >
110+ < Text color = 'white' > { data . latency } </ Text >
111+ < Text dimColor > ms (unloaded)</ Text >
112+ </ >
113+ ) }
114+ { data . latency !== undefined && data . bufferBloat !== undefined && (
115+ < Text dimColor > / </ Text >
116+ ) }
117+ { data . bufferBloat !== undefined && (
118+ < >
119+ < Text color = 'white' > { data . bufferBloat } </ Text >
120+ < Text dimColor > ms (loaded)</ Text >
121+ </ >
122+ ) }
123+ </ >
124+ ) : (
125+ < Text dimColor > Measuring...</ Text >
126+ ) }
127+ </ Box >
128+ < Box >
129+ < Text > < FixedSpacer size = { 4 } /> </ Text >
130+ < Text dimColor > Client: </ Text >
131+ { hasClientData ? (
132+ < >
133+ { data . userLocation && (
134+ < Text color = 'white' > { data . userLocation } </ Text >
135+ ) }
136+ { data . userLocation && data . userIp && (
137+ < Text dimColor > • </ Text >
138+ ) }
139+ { data . userIp && (
140+ < Text color = 'white' > { data . userIp } </ Text >
141+ ) }
142+ </ >
143+ ) : (
144+ < Text dimColor > Detecting...</ Text >
145+ ) }
146+ </ Box >
147+ </ Box >
148+ </ >
149+ ) ;
150+ } ;
151+
152+ function formatVerboseText ( data : PartialSpeedData ) : string [ ] {
153+ const lines : string [ ] = [ ] ;
154+
155+ if ( data . latency !== undefined || data . bufferBloat !== undefined ) {
156+ let latencyLine = 'Latency: ' ;
157+ if ( data . latency !== undefined ) {
158+ latencyLine += `${ data . latency } ms (unloaded)` ;
159+ }
160+
161+ if ( data . latency !== undefined && data . bufferBloat !== undefined ) {
162+ latencyLine += ' / ' ;
163+ }
164+
165+ if ( data . bufferBloat !== undefined ) {
166+ latencyLine += `${ data . bufferBloat } ms (loaded)` ;
167+ }
168+
169+ lines . push ( latencyLine ) ;
170+ }
171+
172+ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
173+ if ( data . userLocation || data . userIp ) {
174+ let clientLine = 'Client: ' ;
175+ if ( data . userLocation ) {
176+ clientLine += data . userLocation ;
177+ }
178+
179+ if ( data . userLocation && data . userIp ) {
180+ clientLine += ' • ' ;
181+ }
182+
183+ if ( data . userIp ) {
184+ clientLine += data . userIp ;
185+ }
186+
187+ lines . push ( clientLine ) ;
188+ }
189+
190+ return lines ;
191+ }
192+
193+ function createJsonOutput ( data : PartialSpeedData , upload : boolean ) {
194+ return {
195+ downloadSpeed : convertToMbps ( data . downloadSpeed ?? 0 , data . downloadUnit ?? 'Mbps' ) ,
196+ uploadSpeed : upload ? convertToMbps ( data . uploadSpeed ?? 0 , data . uploadUnit ?? 'Mbps' ) : undefined ,
197+ downloadUnit : 'Mbps' as const ,
198+ uploadUnit : upload ? 'Mbps' as const : undefined ,
199+ downloaded : data . downloaded ,
200+ uploaded : data . uploaded ,
201+ latency : data . latency ,
202+ bufferBloat : data . bufferBloat ,
203+ userLocation : data . userLocation ,
204+ userIp : data . userIp ,
205+ } ;
206+ }
207+
208+ function formatTextOutput ( data : PartialSpeedData , upload : boolean , verbose : boolean ) : string {
209+ let output = `${ data . downloadSpeed ?? 0 } ${ data . downloadUnit ?? 'Mbps' } ` ;
210+
211+ if ( upload && data . uploadSpeed ) {
212+ output += `\n${ data . uploadSpeed } ${ data . uploadUnit ?? 'Mbps' } ` ;
213+ }
214+
215+ if ( verbose ) {
216+ const verboseLines = formatVerboseText ( data ) ;
217+ if ( verboseLines . length > 0 ) {
218+ output += '\n\n' + verboseLines . join ( '\n' ) ;
219+ }
220+ }
221+
222+ return output ;
223+ }
224+
89225type FastProperties = {
90226 readonly singleLine ?: boolean ;
91227 readonly upload ?: boolean ;
92228 readonly json ?: boolean ;
229+ readonly verbose ?: boolean ;
93230} ;
94231
95- const Ui : React . FC < FastProperties > = ( { singleLine, upload, json} ) => {
232+ const Ui : React . FC < FastProperties > = ( { singleLine, upload, json, verbose } ) => {
96233 const [ error , setError ] = useState ( '' ) ;
97234 const [ data , setData ] = useState < PartialSpeedData > ( { } ) ;
98235 const [ isDone , setIsDone ] = useState ( false ) ;
@@ -137,29 +274,14 @@ const Ui: React.FC<FastProperties> = ({singleLine, upload, json}) => {
137274 }
138275
139276 if ( json ) {
140- const jsonData = {
141- downloadSpeed : convertToMbps ( data . downloadSpeed ?? 0 , data . downloadUnit ?? 'Mbps' ) ,
142- uploadSpeed : upload ? convertToMbps ( data . uploadSpeed ?? 0 , data . uploadUnit ?? 'Mbps' ) : undefined ,
143- downloadUnit : 'Mbps' as const ,
144- uploadUnit : upload ? 'Mbps' as const : undefined ,
145- downloaded : data . downloaded ,
146- uploaded : data . uploaded ,
147- latency : data . latency ,
148- bufferBloat : data . bufferBloat ,
149- userLocation : data . userLocation ,
150- userIp : data . userIp ,
151- } ;
152-
277+ const jsonData = createJsonOutput ( data , Boolean ( upload ) ) ;
153278 write ( JSON . stringify ( jsonData , ( _key , value ) =>
154279 // eslint-disable-next-line @typescript-eslint/no-unsafe-return
155280 value === undefined ? undefined : value ,
156281 '\t' ,
157282 ) ) ;
158283 } else if ( ! process . stdout . isTTY ) {
159- write ( `${ data . downloadSpeed ?? 0 } ${ data . downloadUnit ?? 'Mbps' } ` ) ;
160- if ( upload && data . uploadSpeed ) {
161- write ( `\n${ data . uploadSpeed } ${ data . uploadUnit ?? 'Mbps' } ` ) ;
162- }
284+ write ( formatTextOutput ( data , Boolean ( upload ) , Boolean ( verbose ) ) ) ;
163285 }
164286
165287 exit ( ) ;
@@ -189,6 +311,7 @@ const Ui: React.FC<FastProperties> = ({singleLine, upload, json}) => {
189311 { isDone && < Text > < FixedSpacer size = { 4 } /> </ Text > }
190312 { Object . keys ( data ) . length > 0 && < Speed upload = { upload } data = { data } /> }
191313 </ Box >
314+ { verbose && < VerboseInfo data = { data } singleLine = { singleLine } /> }
192315 < Spacer singleLine = { singleLine } />
193316 </ >
194317 ) ;
0 commit comments