Reboot lock on Hybrid failure and logging fix
This commit is contained in:
@@ -64,7 +64,7 @@ void NukiWrapper::initialize()
|
||||
_nukiLock.registerBleScanner(_bleScanner);
|
||||
_nukiLock.setEventHandler(this);
|
||||
_nukiLock.setConnectTimeout(3);
|
||||
_nukiLock.setDisconnectTimeout(5000);
|
||||
_nukiLock.setDisconnectTimeout(2000);
|
||||
|
||||
_hassEnabled = _preferences->getBool(preference_mqtt_hass_enabled, false);
|
||||
readSettings();
|
||||
@@ -183,11 +183,11 @@ void NukiWrapper::readSettings()
|
||||
_preferences->putInt(preference_restart_ble_beacon_lost, _restartBeaconTimeout);
|
||||
}
|
||||
|
||||
Log->print(F("Lock state interval: "));
|
||||
Log->print(("Lock state interval: "));
|
||||
Log->print(_intervalLockstate);
|
||||
Log->print(F(" | Battery interval: "));
|
||||
Log->print((" | Battery interval: "));
|
||||
Log->print(_intervalBattery);
|
||||
Log->print(F(" | Publish auth data: "));
|
||||
Log->print((" | Publish auth data: "));
|
||||
Log->println(_publishAuthData ? "yes" : "no");
|
||||
|
||||
if(!_publishAuthData)
|
||||
@@ -196,7 +196,7 @@ void NukiWrapper::readSettings()
|
||||
}
|
||||
}
|
||||
|
||||
void NukiWrapper::update()
|
||||
void NukiWrapper::update(bool reboot)
|
||||
{
|
||||
wdt_hal_context_t rtc_wdt_ctx = RWDT_HAL_CONTEXT_DEFAULT();
|
||||
wdt_hal_write_protect_disable(&rtc_wdt_ctx);
|
||||
@@ -204,8 +204,8 @@ void NukiWrapper::update()
|
||||
wdt_hal_write_protect_enable(&rtc_wdt_ctx);
|
||||
if(!_paired)
|
||||
{
|
||||
Log->println(F("Nuki lock start pairing"));
|
||||
_preferences->getBool(preference_register_as_app) ? Log->println(F("Pairing as app")) : Log->println(F("Pairing as bridge"));
|
||||
Log->println(("Nuki lock start pairing"));
|
||||
_preferences->getBool(preference_register_as_app) ? Log->println(("Pairing as app")) : Log->println(("Pairing as bridge"));
|
||||
_network->publishBleAddress("");
|
||||
|
||||
Nuki::AuthorizationIdType idType = _preferences->getBool(preference_register_as_app) ?
|
||||
@@ -214,7 +214,7 @@ void NukiWrapper::update()
|
||||
|
||||
if(_nukiLock.pairNuki(idType) == Nuki::PairingResult::Success)
|
||||
{
|
||||
Log->println(F("Nuki paired"));
|
||||
Log->println(("Nuki paired"));
|
||||
_paired = true;
|
||||
_network->publishBleAddress(_nukiLock.getBleAddress().toString());
|
||||
}
|
||||
@@ -261,14 +261,14 @@ void NukiWrapper::update()
|
||||
NukiLock::cmdResultToString(cmdResult, resultStr);
|
||||
_network->publishCommandResult(resultStr);
|
||||
|
||||
Log->print(F("Lock action result: "));
|
||||
Log->print(("Lock action result: "));
|
||||
Log->println(resultStr);
|
||||
|
||||
if(cmdResult != Nuki::CmdResult::Success)
|
||||
{
|
||||
Log->print(F("Lock: Last command failed, retrying after "));
|
||||
Log->print(("Lock: Last command failed, retrying after "));
|
||||
Log->print(_retryDelay);
|
||||
Log->print(F(" milliseconds. Retry "));
|
||||
Log->print((" milliseconds. Retry "));
|
||||
Log->print(retryCount + 1);
|
||||
Log->print(" of ");
|
||||
Log->println(_nrOfRetries);
|
||||
@@ -291,7 +291,7 @@ void NukiWrapper::update()
|
||||
{
|
||||
_statusUpdated = true;
|
||||
}
|
||||
Log->println(F("Lock: updating status after action"));
|
||||
Log->println(("Lock: updating status after action"));
|
||||
_statusUpdatedTs = ts;
|
||||
if(_intervalLockstate > 10)
|
||||
{
|
||||
@@ -300,7 +300,7 @@ void NukiWrapper::update()
|
||||
}
|
||||
else
|
||||
{
|
||||
Log->println(F("Lock: Maximum number of retries exceeded, aborting."));
|
||||
Log->println(("Lock: Maximum number of retries exceeded, aborting."));
|
||||
_network->publishRetry("failed");
|
||||
retryCount = 0;
|
||||
_nextLockAction = (NukiLock::LockAction) 0xff;
|
||||
@@ -387,6 +387,10 @@ void NukiWrapper::update()
|
||||
{
|
||||
_invalidCount--;
|
||||
}
|
||||
if(reboot && isPinValid())
|
||||
{
|
||||
Nuki::CmdResult cmdResult = _nukiLock.requestReboot();
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(&_lastKeyTurnerState, &_keyTurnerState, sizeof(NukiLock::KeyTurnerState));
|
||||
@@ -458,13 +462,13 @@ bool NukiWrapper::updateKeyTurnerState()
|
||||
Nuki::CmdResult result = (Nuki::CmdResult)-1;
|
||||
int retryCount = 0;
|
||||
|
||||
Log->println(F("Querying lock state"));
|
||||
Log->println(("Querying lock state"));
|
||||
|
||||
while(result != Nuki::CmdResult::Success && retryCount < _nrOfRetries + 1)
|
||||
{
|
||||
Log->print(F("Result (attempt "));
|
||||
Log->print(("Result (attempt "));
|
||||
Log->print(retryCount + 1);
|
||||
Log->print(F("): "));
|
||||
Log->print(("): "));
|
||||
result =_nukiLock.requestKeyTurnerState(&_keyTurnerState);
|
||||
++retryCount;
|
||||
}
|
||||
@@ -481,7 +485,7 @@ bool NukiWrapper::updateKeyTurnerState()
|
||||
postponeBleWatchdog();
|
||||
if(_retryLockstateCount < _nrOfRetries + 1)
|
||||
{
|
||||
Log->print(F("Query lock state retrying in "));
|
||||
Log->print(("Query lock state retrying in "));
|
||||
Log->print(_retryDelay);
|
||||
Log->println("ms");
|
||||
_nextLockStateUpdateTs = espMillis() + _retryDelay;
|
||||
@@ -506,9 +510,9 @@ bool NukiWrapper::updateKeyTurnerState()
|
||||
{
|
||||
if(_publishAuthData && (lockState == NukiLock::LockState::Locked || lockState == NukiLock::LockState::Unlocked))
|
||||
{
|
||||
Log->println(F("Publishing auth data"));
|
||||
Log->println(("Publishing auth data"));
|
||||
updateAuthData(false);
|
||||
Log->println(F("Done publishing auth data"));
|
||||
Log->println(("Done publishing auth data"));
|
||||
}
|
||||
|
||||
updateGpioOutputs();
|
||||
@@ -516,7 +520,7 @@ bool NukiWrapper::updateKeyTurnerState()
|
||||
else if(!_nukiOfficial->getOffConnected() && espMillis() < _statusUpdatedTs + 10000)
|
||||
{
|
||||
updateStatus = true;
|
||||
Log->println(F("Lock: Keep updating status on intermediate lock state"));
|
||||
Log->println(("Lock: Keep updating status on intermediate lock state"));
|
||||
}
|
||||
|
||||
_network->publishKeyTurnerState(_keyTurnerState, _lastKeyTurnerState);
|
||||
@@ -526,7 +530,7 @@ bool NukiWrapper::updateKeyTurnerState()
|
||||
Log->println(lockStateStr);
|
||||
|
||||
postponeBleWatchdog();
|
||||
Log->println(F("Done querying lock state"));
|
||||
Log->println(("Done querying lock state"));
|
||||
return updateStatus;
|
||||
}
|
||||
|
||||
@@ -539,7 +543,7 @@ void NukiWrapper::updateBatteryState()
|
||||
|
||||
while(retryCount < _nrOfRetries + 1)
|
||||
{
|
||||
Log->print(F("Result (attempt "));
|
||||
Log->print(("Result (attempt "));
|
||||
Log->print(retryCount + 1);
|
||||
Log->print("): ");
|
||||
result = _nukiLock.requestBatteryReport(&_batteryReport);
|
||||
@@ -560,7 +564,7 @@ void NukiWrapper::updateBatteryState()
|
||||
_network->publishBatteryReport(_batteryReport);
|
||||
}
|
||||
postponeBleWatchdog();
|
||||
Log->println(F("Done querying lock battery state"));
|
||||
Log->println(("Done querying lock battery state"));
|
||||
}
|
||||
|
||||
void NukiWrapper::updateConfig()
|
||||
@@ -575,7 +579,7 @@ void NukiWrapper::updateConfig()
|
||||
{
|
||||
char uidString[20];
|
||||
itoa(_nukiConfig.nukiId, uidString, 16);
|
||||
Log->print(F("Saving Lock Nuki ID to preferences ("));
|
||||
Log->print(("Saving Lock Nuki ID to preferences ("));
|
||||
Log->print(_nukiConfig.nukiId);
|
||||
Log->print(" / ");
|
||||
Log->print(uidString);
|
||||
@@ -607,7 +611,7 @@ void NukiWrapper::updateConfig()
|
||||
{
|
||||
Nuki::CmdResult result = (Nuki::CmdResult)-1;
|
||||
int retryCount = 0;
|
||||
Log->println(F("Nuki Lock PIN is set"));
|
||||
Log->println(("Nuki Lock PIN is set"));
|
||||
|
||||
while(retryCount < _nrOfRetries + 1)
|
||||
{
|
||||
@@ -624,7 +628,7 @@ void NukiWrapper::updateConfig()
|
||||
|
||||
if(result != Nuki::CmdResult::Success)
|
||||
{
|
||||
Log->println(F("Nuki Lock PIN is invalid"));
|
||||
Log->println(("Nuki Lock PIN is invalid"));
|
||||
if(pinStatus != 2)
|
||||
{
|
||||
_preferences->putInt(preference_lock_pin_status, 2);
|
||||
@@ -632,7 +636,7 @@ void NukiWrapper::updateConfig()
|
||||
}
|
||||
else
|
||||
{
|
||||
Log->println(F("Nuki Lock PIN is valid"));
|
||||
Log->println(("Nuki Lock PIN is valid"));
|
||||
if(pinStatus != 1)
|
||||
{
|
||||
_preferences->putInt(preference_lock_pin_status, 1);
|
||||
@@ -641,7 +645,7 @@ void NukiWrapper::updateConfig()
|
||||
}
|
||||
else
|
||||
{
|
||||
Log->println(F("Nuki Lock PIN is not set"));
|
||||
Log->println(("Nuki Lock PIN is not set"));
|
||||
if(pinStatus != 0)
|
||||
{
|
||||
_preferences->putInt(preference_lock_pin_status, 0);
|
||||
@@ -650,13 +654,13 @@ void NukiWrapper::updateConfig()
|
||||
}
|
||||
else
|
||||
{
|
||||
Log->println(F("Invalid/Unexpected lock config received, ID does not matched saved ID"));
|
||||
Log->println(("Invalid/Unexpected lock config received, ID does not matched saved ID"));
|
||||
expectedConfig = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log->println(F("Invalid/Unexpected lock config received, Config is not valid"));
|
||||
Log->println(("Invalid/Unexpected lock config received, Config is not valid"));
|
||||
expectedConfig = false;
|
||||
}
|
||||
|
||||
@@ -673,7 +677,7 @@ void NukiWrapper::updateConfig()
|
||||
}
|
||||
else
|
||||
{
|
||||
Log->println(F("Invalid/Unexpected lock advanced config received, Advanced config is not valid"));
|
||||
Log->println(("Invalid/Unexpected lock advanced config received, Advanced config is not valid"));
|
||||
expectedConfig = false;
|
||||
}
|
||||
}
|
||||
@@ -681,12 +685,12 @@ void NukiWrapper::updateConfig()
|
||||
if(expectedConfig && _nukiConfigValid && _nukiAdvancedConfigValid)
|
||||
{
|
||||
_retryConfigCount = 0;
|
||||
Log->println(F("Done retrieving lock config and advanced config"));
|
||||
Log->println(("Done retrieving lock config and advanced config"));
|
||||
}
|
||||
else
|
||||
{
|
||||
++_retryConfigCount;
|
||||
Log->println(F("Invalid/Unexpected lock config and/or advanced config received, retrying in 10 seconds"));
|
||||
Log->println(("Invalid/Unexpected lock config and/or advanced config received, retrying in 10 seconds"));
|
||||
int64_t ts = espMillis();
|
||||
_nextConfigUpdateTs = ts + 10000;
|
||||
}
|
||||
@@ -696,7 +700,7 @@ void NukiWrapper::updateAuthData(bool retrieved)
|
||||
{
|
||||
if(!isPinValid())
|
||||
{
|
||||
Log->println(F("No valid Nuki Lock PIN set"));
|
||||
Log->println(("No valid Nuki Lock PIN set"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -707,7 +711,7 @@ void NukiWrapper::updateAuthData(bool retrieved)
|
||||
|
||||
while(retryCount < _nrOfRetries + 1)
|
||||
{
|
||||
Log->print(F("Retrieve log entries: "));
|
||||
Log->print(("Retrieve log entries: "));
|
||||
result = _nukiLock.retrieveLogEntries(0, _preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG), 1, false);
|
||||
if(result != Nuki::CmdResult::Success)
|
||||
{
|
||||
@@ -759,7 +763,7 @@ void NukiWrapper::updateAuthData(bool retrieved)
|
||||
return a.index < b.index;
|
||||
});
|
||||
|
||||
Log->print(F("Log size: "));
|
||||
Log->print(("Log size: "));
|
||||
Log->println(log.size());
|
||||
|
||||
if(log.size() > 0)
|
||||
@@ -780,7 +784,7 @@ void NukiWrapper::updateKeypad(bool retrieved)
|
||||
|
||||
if(!isPinValid())
|
||||
{
|
||||
Log->println(F("No valid Nuki Lock PIN set"));
|
||||
Log->println(("No valid Nuki Lock PIN set"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -791,7 +795,7 @@ void NukiWrapper::updateKeypad(bool retrieved)
|
||||
|
||||
while(retryCount < _nrOfRetries + 1)
|
||||
{
|
||||
Log->print(F("Querying lock keypad: "));
|
||||
Log->print(("Querying lock keypad: "));
|
||||
result = _nukiLock.retrieveKeypadEntries(0, _preferences->getInt(preference_keypad_max_entries, MAX_KEYPAD));
|
||||
if(result != Nuki::CmdResult::Success)
|
||||
{
|
||||
@@ -814,7 +818,7 @@ void NukiWrapper::updateKeypad(bool retrieved)
|
||||
std::list<NukiLock::KeypadEntry> entries;
|
||||
_nukiLock.getKeypadEntries(&entries);
|
||||
|
||||
Log->print(F("Lock keypad codes: "));
|
||||
Log->print(("Lock keypad codes: "));
|
||||
Log->println(entries.size());
|
||||
|
||||
entries.sort([](const NukiLock::KeypadEntry& a, const NukiLock::KeypadEntry& b)
|
||||
@@ -859,7 +863,7 @@ void NukiWrapper::updateTimeControl(bool retrieved)
|
||||
|
||||
if(!isPinValid())
|
||||
{
|
||||
Log->println(F("No valid Nuki Lock PIN set"));
|
||||
Log->println(("No valid Nuki Lock PIN set"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -870,7 +874,7 @@ void NukiWrapper::updateTimeControl(bool retrieved)
|
||||
|
||||
while(retryCount < _nrOfRetries + 1)
|
||||
{
|
||||
Log->print(F("Querying lock timecontrol: "));
|
||||
Log->print(("Querying lock timecontrol: "));
|
||||
result = _nukiLock.retrieveTimeControlEntries();
|
||||
if(result != Nuki::CmdResult::Success)
|
||||
{
|
||||
@@ -893,7 +897,7 @@ void NukiWrapper::updateTimeControl(bool retrieved)
|
||||
std::list<NukiLock::TimeControlEntry> timeControlEntries;
|
||||
_nukiLock.getTimeControlEntries(&timeControlEntries);
|
||||
|
||||
Log->print(F("Lock timecontrol entries: "));
|
||||
Log->print(("Lock timecontrol entries: "));
|
||||
Log->println(timeControlEntries.size());
|
||||
|
||||
timeControlEntries.sort([](const NukiLock::TimeControlEntry& a, const NukiLock::TimeControlEntry& b)
|
||||
@@ -930,7 +934,7 @@ void NukiWrapper::updateAuth(bool retrieved)
|
||||
{
|
||||
if(!isPinValid())
|
||||
{
|
||||
Log->println(F("No valid Nuki Lock PIN set"));
|
||||
Log->println(("No valid Nuki Lock PIN set"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -946,7 +950,7 @@ void NukiWrapper::updateAuth(bool retrieved)
|
||||
|
||||
while(retryCount < _nrOfRetries)
|
||||
{
|
||||
Log->print(F("Querying lock authorization: "));
|
||||
Log->print(("Querying lock authorization: "));
|
||||
result = _nukiLock.retrieveAuthorizationEntries(0, _preferences->getInt(preference_auth_max_entries, MAX_AUTH));
|
||||
delay(250);
|
||||
if(result != Nuki::CmdResult::Success)
|
||||
@@ -970,7 +974,7 @@ void NukiWrapper::updateAuth(bool retrieved)
|
||||
std::list<NukiLock::AuthorizationEntry> authEntries;
|
||||
_nukiLock.getAuthorizationEntries(&authEntries);
|
||||
|
||||
Log->print(F("Lock authorization entries: "));
|
||||
Log->print(("Lock authorization entries: "));
|
||||
Log->println(authEntries.size());
|
||||
|
||||
authEntries.sort([](const NukiLock::AuthorizationEntry& a, const NukiLock::AuthorizationEntry& b)
|
||||
@@ -2760,7 +2764,7 @@ void NukiWrapper::onKeypadJsonCommandReceived(const char *value)
|
||||
{
|
||||
auto it1 = std::find(_keypadCodeIds.begin(), _keypadCodeIds.end(), codeId);
|
||||
int index = it1 - _keypadCodeIds.begin();
|
||||
Log->print(F("Check keypad code: "));
|
||||
Log->print(("Check keypad code: "));
|
||||
|
||||
if(code == _keypadCodes[index])
|
||||
{
|
||||
@@ -2800,7 +2804,7 @@ void NukiWrapper::onKeypadJsonCommandReceived(const char *value)
|
||||
if(idExists)
|
||||
{
|
||||
result = _nukiLock.deleteKeypadEntry(codeId);
|
||||
Log->print(F("Delete keypad code: "));
|
||||
Log->print(("Delete keypad code: "));
|
||||
Log->println((int)result);
|
||||
}
|
||||
else
|
||||
@@ -3007,7 +3011,7 @@ void NukiWrapper::onKeypadJsonCommandReceived(const char *value)
|
||||
}
|
||||
|
||||
result = _nukiLock.addKeypadEntry(entry);
|
||||
Log->print(F("Add keypad code: "));
|
||||
Log->print(("Add keypad code: "));
|
||||
Log->println((int)result);
|
||||
}
|
||||
else if (strcmp(action, "update") == 0)
|
||||
@@ -3173,7 +3177,7 @@ void NukiWrapper::onKeypadJsonCommandReceived(const char *value)
|
||||
}
|
||||
|
||||
result = _nukiLock.updateKeypadEntry(entry);
|
||||
Log->print(F("Update keypad code: "));
|
||||
Log->print(("Update keypad code: "));
|
||||
Log->println((int)result);
|
||||
}
|
||||
}
|
||||
@@ -3300,7 +3304,7 @@ void NukiWrapper::onTimeControlCommandReceived(const char *value)
|
||||
if(idExists)
|
||||
{
|
||||
result = _nukiLock.removeTimeControlEntry(entryId);
|
||||
Log->print(F("Delete timecontrol: "));
|
||||
Log->print(("Delete timecontrol: "));
|
||||
Log->println((int)result);
|
||||
}
|
||||
else
|
||||
@@ -3380,7 +3384,7 @@ void NukiWrapper::onTimeControlCommandReceived(const char *value)
|
||||
entry.lockAction = timeControlLockAction;
|
||||
|
||||
result = _nukiLock.addTimeControlEntry(entry);
|
||||
Log->print(F("Add timecontrol: "));
|
||||
Log->print(("Add timecontrol: "));
|
||||
Log->println((int)result);
|
||||
}
|
||||
else if (strcmp(action, "update") == 0)
|
||||
@@ -3458,7 +3462,7 @@ void NukiWrapper::onTimeControlCommandReceived(const char *value)
|
||||
entry.lockAction = timeControlLockAction;
|
||||
|
||||
result = _nukiLock.updateTimeControlEntry(entry);
|
||||
Log->print(F("Update timecontrol: "));
|
||||
Log->print(("Update timecontrol: "));
|
||||
Log->println((int)result);
|
||||
}
|
||||
}
|
||||
@@ -3613,7 +3617,7 @@ void NukiWrapper::onAuthCommandReceived(const char *value)
|
||||
{
|
||||
result = _nukiLock.deleteAuthorizationEntry(authId);
|
||||
delay(250);
|
||||
Log->print(F("Delete authorization: "));
|
||||
Log->print(("Delete authorization: "));
|
||||
Log->println((int)result);
|
||||
}
|
||||
else
|
||||
@@ -3833,7 +3837,7 @@ void NukiWrapper::onAuthCommandReceived(const char *value)
|
||||
|
||||
result = _nukiLock.addAuthorizationEntry(entry);
|
||||
delay(250);
|
||||
Log->print(F("Add authorization: "));
|
||||
Log->print(("Add authorization: "));
|
||||
Log->println((int)result);
|
||||
}
|
||||
else if (strcmp(action, "update") == 0)
|
||||
@@ -3999,7 +4003,7 @@ void NukiWrapper::onAuthCommandReceived(const char *value)
|
||||
|
||||
result = _nukiLock.updateAuthorizationEntry(entry);
|
||||
delay(250);
|
||||
Log->print(F("Update authorization: "));
|
||||
Log->print(("Update authorization: "));
|
||||
Log->println((int)result);
|
||||
}
|
||||
}
|
||||
@@ -4103,7 +4107,7 @@ void NukiWrapper::readConfig()
|
||||
|
||||
char resultStr[20];
|
||||
NukiLock::cmdResultToString(result, resultStr);
|
||||
Log->print(F("Lock config result: "));
|
||||
Log->print(("Lock config result: "));
|
||||
Log->println(resultStr);
|
||||
|
||||
if(result != Nuki::CmdResult::Success)
|
||||
@@ -4131,7 +4135,7 @@ void NukiWrapper::readAdvancedConfig()
|
||||
|
||||
char resultStr[20];
|
||||
NukiLock::cmdResultToString(result, resultStr);
|
||||
Log->print(F("Lock advanced config result: "));
|
||||
Log->print(("Lock advanced config result: "));
|
||||
Log->println(resultStr);
|
||||
|
||||
if(result != Nuki::CmdResult::Success)
|
||||
@@ -4211,7 +4215,7 @@ void NukiWrapper::updateTime()
|
||||
{
|
||||
if(!isPinValid())
|
||||
{
|
||||
Log->println(F("No valid PIN set"));
|
||||
Log->println(("No valid PIN set"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4222,7 +4226,7 @@ void NukiWrapper::updateTime()
|
||||
|
||||
if (int(tm.tm_year + 1900) < int(2025))
|
||||
{
|
||||
Log->println(F("NTP Time not valid, not updating Nuki device"));
|
||||
Log->println(("NTP Time not valid, not updating Nuki device"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4239,6 +4243,6 @@ void NukiWrapper::updateTime()
|
||||
char resultStr[15] = {0};
|
||||
NukiLock::cmdResultToString(cmdResult, resultStr);
|
||||
|
||||
Log->print(F("Lock time update result: "));
|
||||
Log->print(("Lock time update result: "));
|
||||
Log->println(resultStr);
|
||||
}
|
||||
Reference in New Issue
Block a user