package dao import ( "errors" "hy2xs-admin/model/constant" ) // Отличать «строки нет» от «база не ответила» обязан слой данных. // // Что было. Каждый Get* возвращал `errors.New(constant.WrongPassword)` для // gorm.ErrRecordNotFound и `errors.New(constant.SysError)` для всего // остального. Обе — свежие значения ошибки со строкой внутри, поэтому // вызывающий мог отличить одно от другого только сравнением текста, чего никто // не делал: везде проверялось `err != nil` или `err == nil`. // // Из-за этого сбой SQLite неотличим от отсутствия записи, а решения на этом // принимаются серьёзные: // // ensureSecureBootstrapPeer — «пира нет» означает «создать пир заново»; // applyPeerImportEntry — «по auth_id не нашли» означает «искать по имени» // и, не найдя, СОЗДАТЬ запись; // ExistPeerName — «ошибка» означает «имя свободно». // // То есть при недоступной базе продукт не отказывал, а трактовал отказ как // разрешение действовать. Транзакция спасает целостность, но не смысл: решение // уже принято неверно к моменту записи. // // Значения объявлены один раз и возвращаются как есть, поэтому работает // errors.Is. Тексты сохранены прежними: WrongPassword уезжает в ответ Hysteria // при неудачной machine-auth, и менять его здесь было бы изменением внешнего // контракта ради внутренней аккуратности. var ( // ErrPeerNotFound — пира с такими условиями в базе нет. ErrPeerNotFound = errors.New(constant.WrongPassword) // ErrAdminUserNotFound — учётной записи администратора нет. ErrAdminUserNotFound = errors.New(constant.WrongPassword) // ErrConfigNotFound — строки с таким ключом в таблице `config` нет. ErrConfigNotFound = errors.New(constant.ConfigNotExist) // ErrStorage — база не смогла ответить. Не «нет данных», а «неизвестно». ErrStorage = errors.New(constant.SysError) ) // IsNotFound — истина только для «записи нет», и никогда для отказа хранилища. // // Помощник существует, чтобы у вызывающих был ровно один способ задать этот // вопрос: три разных sentinel'а для трёх таблиц иначе неизбежно проверялись бы // по-разному в разных местах. func IsNotFound(err error) bool { return errors.Is(err, ErrPeerNotFound) || errors.Is(err, ErrAdminUserNotFound) || errors.Is(err, ErrConfigNotFound) }