mirror of
https://github.com/MengMengCode/VoCat.git
synced 2026-08-17 13:23:42 +08:00
85 lines
2.3 KiB
Go
85 lines
2.3 KiB
Go
package device
|
|
|
|
import (
|
|
"regexp"
|
|
"strings"
|
|
"unicode"
|
|
|
|
"vocat/internal/modem"
|
|
)
|
|
|
|
const maxHardwareErrorDetail = 1024
|
|
|
|
var longHexPayload = regexp.MustCompile(`(?i)\b[0-9a-f]{48,}\b`)
|
|
|
|
// HardwareErrorDetail returns a diagnostic error suitable for persistent and
|
|
// browser-visible logs. AT payloads can contain APDU authentication material,
|
|
// SMS data, or APN credentials, so CommandError values retain only the command
|
|
// name and modem final result. Very long hexadecimal payloads from wrapped
|
|
// protocol errors are removed as a second line of defence.
|
|
func HardwareErrorDetail(err error) string {
|
|
if err == nil {
|
|
return ""
|
|
}
|
|
detail := redactCommandErrors(err.Error(), err)
|
|
detail = longHexPayload.ReplaceAllString(detail, "[redacted hex payload]")
|
|
detail = strings.Map(func(character rune) rune {
|
|
if unicode.IsControl(character) && character != '\t' && character != '\n' {
|
|
return ' '
|
|
}
|
|
return character
|
|
}, strings.TrimSpace(detail))
|
|
runes := []rune(detail)
|
|
if len(runes) > maxHardwareErrorDetail {
|
|
detail = string(runes[:maxHardwareErrorDetail]) + "..."
|
|
}
|
|
return detail
|
|
}
|
|
|
|
func redactCommandErrors(detail string, err error) string {
|
|
if commandErr, ok := err.(*modem.CommandError); ok {
|
|
detail = strings.ReplaceAll(detail, commandErr.Error(), safeCommandError(commandErr))
|
|
}
|
|
switch wrapped := err.(type) {
|
|
case interface{ Unwrap() []error }:
|
|
for _, child := range wrapped.Unwrap() {
|
|
detail = redactCommandErrors(detail, child)
|
|
}
|
|
case interface{ Unwrap() error }:
|
|
if child := wrapped.Unwrap(); child != nil {
|
|
detail = redactCommandErrors(detail, child)
|
|
}
|
|
}
|
|
return detail
|
|
}
|
|
|
|
func safeCommandError(err *modem.CommandError) string {
|
|
command := safeATCommandName(err.Command)
|
|
final := strings.TrimSpace(err.Final)
|
|
if final == "" {
|
|
final = "unknown modem error"
|
|
}
|
|
return command + " failed: " + final
|
|
}
|
|
|
|
func safeATCommandName(command string) string {
|
|
command = strings.ToUpper(strings.TrimSpace(command))
|
|
if command == "" {
|
|
return "AT command"
|
|
}
|
|
if strings.HasPrefix(command, "ATD") {
|
|
return "ATD"
|
|
}
|
|
for index, character := range command {
|
|
if character == '=' || character == '?' || character == ',' ||
|
|
character == '"' || unicode.IsSpace(character) {
|
|
command = command[:index]
|
|
break
|
|
}
|
|
}
|
|
if !strings.HasPrefix(command, "AT") || len(command) > 32 {
|
|
return "AT command"
|
|
}
|
|
return command
|
|
}
|