-
Notifications
You must be signed in to change notification settings - Fork 165
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unify remaining std::error_codes into Status/ErrorCodes in sync client #6869
Unify remaining std::error_codes into Status/ErrorCodes in sync client #6869
Conversation
@@ -485,8 +485,14 @@ static inline realm_version_id_t to_capi(const VersionID& v) | |||
return version_id; | |||
} | |||
|
|||
realm_sync_error_code_t to_capi(const Status& status, std::string& message); | |||
void sync_error_to_error_code(const realm_sync_error_code_t& sync_error_code, std::error_code* error_code_out); | |||
static inline realm_error_t to_capi(const Status s) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: keep the const&
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
util::Optional<ShouldBackup> delete_file; | ||
bool log_out_user = false; | ||
bool unrecognized_by_client = false; | ||
|
||
// Can be called from within SyncSession with an AuthError to handle app-level authentication problems, | ||
// so even if there's an error action, we need to set a fall-back to logging out the user and making |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when there is no error action (i.e, a synthetized error), we'll set unrecognized_by_client
to true. I don't think we want that. This behavior is different than before.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whoops. I've actually mis-understood this code flow a bit and I've changed this so that if you want this behavior you need to pass in an action of LogOutUser
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
} | ||
|
||
std::error_code get_std_error_code() const | ||
Status(ErrorCodes::Error code, std::string&& reason) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want/need both constructors?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, so the first constructor makes a copy of a string. This constructor is if you've just created a Status with a new string via util::format() or something. So this is just a little optimization to avoid an allocation/copy.
SessionErrorInfo(const ProtocolErrorInfo& info, Status status) | ||
: ProtocolErrorInfo(info) | ||
, status(std::move(status)) | ||
{ | ||
} | ||
|
||
SessionErrorInfo(Status status, IsFatal is_fatal) | ||
: ProtocolErrorInfo(status.get_std_error_code().value(), status.reason(), is_fatal) | ||
: ProtocolErrorInfo(0, {}, is_fatal) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't we pass the info from status
to the ProtocolErrorInfo constructor?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this is the case where if you are constructing a SessionErrorInfo for something besides a protocol error. I wasn't sure what the right thing to do here is/was, but I settled on leaving the ProtocolErrorInfo portion of the class in an invalid state rather than trying to reverse-translate Status's to ProtocolErrors.
return {ErrorCodes::SyncProtocolInvariantFailed, | ||
util::format("Received ERROR message with unknown error code %1", info.raw_error_code)}; | ||
auto status = protocol_error_to_status(static_cast<ProtocolError>(info.raw_error_code), info.message); | ||
// If the server has requested an action but sent an invalid error code we can still process the error and pass an |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the assumption is that the server always sends an action (cc @tkaye407), so maybe an assert is more appropriate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The server should always send an action, yes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addendum: we will only do it for realm devices that know about the JSONErrorMessage, but I dont think that matters in this case
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going to fix this in a separate PR.
if (status == ErrorCodes::UnknownError && info.server_requests_action != ProtocolErrorInfo::Action::NoAction) { | ||
return { | ||
ErrorCodes::SyncProtocolInvariantFailed, | ||
util::format("Received ERROR message with unknown error code %1 and no action.", info.raw_error_code)}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
an action is received in this case
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, this logic is wrong I've undone it and will fix it up in a separate review.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll take that you'll update this message as well in that pr.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes
} | ||
if (user) { | ||
user->log_out(); | ||
} | ||
|
||
if (auto error_handler = config(&SyncConfig::error_handler)) { | ||
auto user_facing_error = | ||
SyncError(Status{realm::sync::ProtocolError::bad_authentication, context_message}, true); | ||
auto user_facing_error = SyncError({ErrorCodes::AuthError, status.reason()}, true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you need to set the correct action (LogOutUser).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So my confusion here is that this is not getting passed to handle_error()
, it's getting passed to error_handler
and the action actually has no effect. I can set it here for completeness, but it's not going to get used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, I see. It's calling the user callback directly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is it the right thing though? 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what you mean? What else would we do here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so I was wondering if we should call handle_error()
instead, so we actually log out the user.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But we log out the user right above on line 248
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I completely missed that. I think the only difference (from being handled in handle_error()) then is that the session may remain active. But it's the same as before so maybe not an issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The session should already be closed at this point: this path is called when a SyncSession is being revived and will never become_active()
on a bad auth or if the websocket connection failed for bad auth or redirect during open.
@@ -364,34 +365,17 @@ enum class ProtocolError { | |||
// clang-format on | |||
}; | |||
|
|||
Status protocol_error_to_status(ProtocolError raw_error_code, std::string_view msg); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you have this declared at line 377.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed. I think this was a merge issue 😞
case ProtocolError::client_file_expired: | ||
[[fallthrough]]; | ||
case ProtocolError::bad_client_file: | ||
return ErrorCodes::SyncClientResetRequired; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there are probably other cases when a client reset is required (e.g, migrate_to_flx). what is this used for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are error codes that specifically always mean that you should client reset. migrate_to_flx has the error code WrongSyncType.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good - there's a lot of good changes (and a lot of work) in the error unification project.
Two tiny comments
@@ -712,8 +712,7 @@ class MultiClientServerFixture { | |||
return; | |||
REALM_ASSERT(error); | |||
unit_test::TestContext& test_context = m_test_context; | |||
test_context.logger->error("Client disconnect: %1: %2 (is_fatal=%3)", | |||
error->status.get_std_error_code(), error->message, error->is_fatal); | |||
test_context.logger->error("Client disconnect: %1 (is_fatal=%3)", error->status, error->is_fatal); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is_fatal
index is wrong
// sync websocket is closed with specific error codes. | ||
RefreshUser, | ||
RefreshLocation, | ||
LogOutUser, | ||
}; | ||
|
||
ProtocolErrorInfo() = default; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't related to your changes, but should we explicitly set the default value for server_requests_action
to be Action::NoAction
- the compiler will use whatever value is at 0, whatever it is...
* Add new ErrorCodes for sync error unification (#6829) * Make SyncError/SessionErrorInfo Status-aware (#6824) * Replace ClientError error_code with ErrorCodes/Status (#6846) * Handle websocket errors entirely within sync client (#6859) * Unify remaining std::error_codes into Status/ErrorCodes in sync client (#6869) * fix changelog merge with master
What, How & Why?
This is the last step of the big error unification refactor. It moves translation of ProtocolError codes into realm ErrorCodes into the sync client. It removes std::error_code from Status and friends. It adjusts tests that were depending on old std::error_code values.
☑️ ToDos