import {Platform} from 'react-native' /** * Detect connection type from address format * @param address Device address (MAC, UUID, or IP:PORT) * @returns Connection type: 'ble', 'bt', 'lan', or null if cannot detect */ export function detectAddressType(address: string): 'ble' | 'bt' | 'lan' | null { if (!address) return null // Check if already has type prefix if (address.startsWith('ble:') || address.startsWith('bt:') || address.startsWith('lan:')) { return address.split(':')[0] as 'ble' | 'bt' | 'lan' } // LAN: IP address format (with or without port) // IPv4: xxx.xxx.xxx.xxx or xxx.xxx.xxx.xxx:port const ipv4Pattern = /^(\d{1,3}\.){3}\d{1,3}(:\d{1,5})?$/ if (ipv4Pattern.test(address)) { return 'lan' } // BLE on iOS: UUID format // Format: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX (8-4-4-4-12) const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i if (uuidPattern.test(address)) { return 'ble' } // Bluetooth Classic/BLE on Android: MAC address // Format: XX:XX:XX:XX:XX:XX const macPattern = /^([0-9a-f]{2}:){5}[0-9a-f]{2}$/i if (macPattern.test(address)) { // On iOS, MAC addresses are usually BLE // On Android, could be either BLE or Classic // Default to 'bt' for Android, 'ble' for iOS return Platform.OS === 'ios' ? 'ble' : 'bt' } // IPv6 (less common for printers) if (address.includes('::') || address.split(':').length > 6) { return 'lan' } return null } /** * Helper function to build printer address * @param typeOrAddress Connection type ('ble', 'bt', 'lan') or just the address * @param identifier Optional device identifier if type is provided * @returns Formatted address string * @example * buildAddress('ble', 'XX:XX:XX:XX:XX:XX') => 'ble:XX:XX:XX:XX:XX:XX' * buildAddress('192.168.1.100:9100') => 'lan:192.168.1.100:9100' * buildAddress('XX:XX:XX:XX:XX:XX') => 'bt:XX:XX:XX:XX:XX:XX' (Android) or 'ble:XX:XX:XX:XX:XX:XX' (iOS) */ export function buildAddress(typeOrAddress: string, identifier?: string): string { // If identifier is provided, treat first param as type if (identifier) { return `${typeOrAddress}:${identifier}` } // Otherwise, first param is the address - detect type const address = typeOrAddress // Check if already formatted if (address.includes(':')) { const parts = address.split(':') if (['ble', 'bt', 'lan'].includes(parts[0])) { return address // Already formatted } } // Auto-detect type const detectedType = detectAddressType(address) if (detectedType) { return `${detectedType}:${address}` } // If cannot detect, assume based on platform console.warn(`[JS] ConnectionUtils.normalizeAddress - WARN: Cannot detect type for ${address}, using platform default`) const defaultType = Platform.OS === 'ios' ? 'ble' : 'bt' return `${defaultType}:${address}` } /** * Helper function to parse printer address * @param address Printer address * @returns Object with type and identifier */ export function parseAddress(address: string): {type: string; identifier: string} { const [type, ...parts] = address.split(':') return { type, identifier: parts.join(':'), } }