// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {loadTimeData} from 'chrome://resources/ash/common/load_time_data.m.js';
import {assert, assertNotReached} from 'chrome://resources/js/assert.js';
import {NavigationView, RoutineProperties} from './diagnostics_types.js';
import {LockType, Network, NetworkState, NetworkType} from './network_health_provider.mojom-webui.js';
import {RoutineGroup} from './routine_group.js';
import {RoutineType} from './system_routine_controller.mojom-webui.js';
/**
* Converts a KiB storage value to GiB and returns a fixed-point string
* to the desired number of decimal places.
*/
export function convertKibToGibDecimalString(
value: number, numDecimalPlaces: number): string {
return (value / 2 ** 20).toFixed(numDecimalPlaces);
}
/** Converts a KiB storage value to MiB. */
export function convertKibToMib(value: number): number {
// 1024 KiB is 1 MiB.
return value / (2 ** 10);
}
/** Returns an icon from the diagnostics icon set. */
export function getDiagnosticsIcon(id: string): string {
return `diagnostics:${id}`;
}
/** Returns an icon from the navigation icon set. */
export function getNavigationIcon(id: string): string {
return `navigation-selector:${id}`;
}
/**
* Converts ID into matching navigation view. ID matches the 'id' field provided
* to the navigation-view-panel {SelectorItem} array.
*/
export function getNavigationViewForPageId(id: string): NavigationView {
switch (id) {
case 'system':
return NavigationView.SYSTEM;
case 'connectivity':
return NavigationView.CONNECTIVITY;
case 'input':
return NavigationView.INPUT;
default:
assertNotReached();
}
}
export function getNetworkType(type: NetworkType): string {
switch (type) {
case NetworkType.kWiFi:
return loadTimeData.getString('wifiLabel');
case NetworkType.kEthernet:
return loadTimeData.getString('ethernetLabel');
case NetworkType.kCellular:
return loadTimeData.getString('cellularLabel');
}
assertNotReached();
}
export function getNetworkState(state: NetworkState): string {
switch (state) {
case NetworkState.kOnline:
return loadTimeData.getString('networkStateOnlineText');
case NetworkState.kConnected:
return loadTimeData.getString('networkStateConnectedText');
case NetworkState.kPortal:
return loadTimeData.getString('networkStatePortalText');
case NetworkState.kConnecting:
return loadTimeData.getString('networkStateConnectingText');
case NetworkState.kNotConnected:
return loadTimeData.getString('networkStateNotConnectedText');
case NetworkState.kDisabled:
return loadTimeData.getString('networkStateDisabledText');
}
assertNotReached();
}
export function getLockType(lockType: LockType): string {
switch (lockType) {
case LockType.kSimPuk:
return 'sim-puk';
case LockType.kSimPin:
return 'sim-pin';
case LockType.kNetworkPin:
return 'network-pin';
case LockType.kNone:
return '';
}
assertNotReached();
}
/**
* @param blocking If a routine is blocking, the remaining routines
* will be skipped. For non-blocking routines, we'll continue running them
* and display a 'WARNING' badge to signal that a non-blocking routine failed.
*/
export function createRoutine(
routine: RoutineType, blocking: boolean): RoutineProperties {
return {routine, blocking};
}
export function getRoutineGroups(type: NetworkType): RoutineGroup[] {
const localNetworkGroup = new RoutineGroup(
[
createRoutine(RoutineType.kGatewayCanBePinged, false),
createRoutine(RoutineType.kLanConnectivity, true),
createRoutine(RoutineType.kArcPing, false),
],
'localNetworkGroupLabel');
const nameResolutionGroup = new RoutineGroup(
[
createRoutine(RoutineType.kDnsResolverPresent, true),
createRoutine(RoutineType.kDnsResolution, true),
createRoutine(RoutineType.kDnsLatency, true),
createRoutine(RoutineType.kArcDnsResolution, false),
],
'nameResolutionGroupLabel');
const wifiGroup = new RoutineGroup(
[
createRoutine(RoutineType.kSignalStrength, false),
createRoutine(RoutineType.kCaptivePortal, false),
createRoutine(RoutineType.kHasSecureWiFiConnection, false),
],
'wifiGroupLabel');
const internetConnectivityGroup = new RoutineGroup(
[
createRoutine(RoutineType.kHttpsFirewall, true),
createRoutine(RoutineType.kHttpFirewall, true),
createRoutine(RoutineType.kHttpsLatency, true),
createRoutine(RoutineType.kArcHttp, false),
],
'internetConnectivityGroupLabel');
const groupsToAdd = type === NetworkType.kWiFi ?
[wifiGroup, internetConnectivityGroup] :
[internetConnectivityGroup];
const networkRoutineGroups = [
localNetworkGroup,
nameResolutionGroup,
];
return networkRoutineGroups.concat(groupsToAdd);
}
export function getSubnetMaskFromRoutingPrefix(prefix: number): string {
// TODO(wenyu): Handle IPv6 type with prefix range of [1, 128].
assert(prefix >= 0 && prefix <= 32);
// A routing prefix can not be 0. Zero indicates an unset value.
if (prefix === 0) {
return '';
}
const zeroes = 32 - prefix;
// Note: 0xffffffff is 32 bits, all set to 1.
// Use << to knock off |zeroes| number of bits and then use that same number
// to replace those bits with zeroes.
// Ex: 11111111 11111111 11111111 11111111 becomes
// 11111111 11111111 11111111 00000000.
let mask = (0xffffffff >> zeroes) << zeroes;
const pieces = new Array(4);
for (let i = 0; i < 4; i++) {
// Note: & is binary and. 0xff is 8 ones "11111111".
// Use & with the mask to select the bits from the other number.
// Repeat to split the 32 bit number into four 8-bit numbers
pieces[3 - i] = mask & 0xff;
mask = mask >> 8;
}
return pieces.join('.');
}
export function formatMacAddress(macAddress: string): string {
return `${loadTimeData.getString('macAddressLabel')}: ${macAddress}`;
}
/**
* Resolves a networking routine type to its corresponding localized failure
* message.
*/
export function getRoutineFailureMessage(routineType: RoutineType): string {
switch (routineType) {
case RoutineType.kCaptivePortal:
return loadTimeData.getString('captivePortalFailedText');
case RoutineType.kDnsLatency:
return loadTimeData.getString('dnsLatencyFailedText');
case RoutineType.kDnsResolution:
return loadTimeData.getString('dnsResolutionFailedText');
case RoutineType.kDnsResolverPresent:
return loadTimeData.getString('dnsResolverPresentFailedText');
case RoutineType.kGatewayCanBePinged:
return loadTimeData.getString('gatewayCanBePingedFailedText');
case RoutineType.kHasSecureWiFiConnection:
return loadTimeData.getString('hasSecureWiFiConnectionFailedText');
case RoutineType.kHttpFirewall:
return loadTimeData.getString('httpFirewallFailedText');
case RoutineType.kHttpsFirewall:
return loadTimeData.getString('httpsFirewallFailedText');
case RoutineType.kHttpsLatency:
return loadTimeData.getString('httpsLatencyFailedText');
case RoutineType.kLanConnectivity:
return loadTimeData.getString('lanConnectivityFailedText');
case RoutineType.kSignalStrength:
return loadTimeData.getString('signalStrengthFailedText');
case RoutineType.kArcHttp:
return loadTimeData.getString('arcHttpFailedText');
case RoutineType.kArcPing:
return loadTimeData.getString('arcPingFailedText');
case RoutineType.kArcDnsResolution:
return loadTimeData.getString('arcDnsResolutionFailedText');
case RoutineType.kBatteryCharge:
case RoutineType.kBatteryDischarge:
case RoutineType.kCpuCache:
case RoutineType.kCpuStress:
case RoutineType.kCpuFloatingPoint:
case RoutineType.kCpuPrime:
case RoutineType.kMemory:
default:
// Values should always be found in the enum.
assertNotReached();
}
}
export function isConnectedOrOnline(state: NetworkState): boolean {
switch (state) {
case NetworkState.kOnline:
case NetworkState.kConnected:
case NetworkState.kConnecting:
return true;
default:
return false;
}
}
export function isNetworkMissingNameServers(network: Network): boolean {
return !network.ipConfig || !network.ipConfig.nameServers ||
network.ipConfig.nameServers.length === 0;
}
/** Removes '0.0.0.0' from list of name servers. */
export function filterNameServers(network: Network): void {
if (network?.ipConfig?.nameServers) {
network.ipConfig.nameServers =
network.ipConfig.nameServers.filter((n: string) => n !== '0.0.0.0');
}
}
/*
* If true network state text is appended to network and connectivity card
* title.
* @type {boolean}
*/
let displayStateInTitle = false;
/**
* Test helper function to allow change if state text is appended to the card
* title.
*/
export function setDisplayStateInTitleForTesting(state: boolean): void {
displayStateInTitle = state;
}
/**
* Build common string for network title for network and connectivity card.
* Current network state is included for debugging when `displayStateInTitle`
* is true.
*/
export function getNetworkCardTitle(
networkType: string, networkState: string): string {
let titleForCard = `${networkType}`;
if (displayStateInTitle) {
titleForCard = `${titleForCard} (${networkState})`;
}
return `${titleForCard}`;
}
export function getSignalStrength(value: number): string {
assert(typeof value === 'number');
assert(value >= 0 && value <= 100);
if (value <= 1) {
return '';
}
if (value <= 25) {
return loadTimeData.getStringF('signalStrength_Weak', value);
}
if (value <= 50) {
return loadTimeData.getStringF('signalStrength_Average', value);
}
if (value <= 75) {
return loadTimeData.getStringF('signalStrength_Good', value);
}
return loadTimeData.getStringF('signalStrength_Excellent', value);
}