mirror of
https://github.com/RGBCube/serenity
synced 2025-07-10 06:07:35 +00:00
LibCore+Userland: Allow canceling promises
To make EventLoop cancel its managed Promises, we need the ability to cancel them in the first place.
This commit is contained in:
parent
afd0f941b7
commit
bfd9f681f7
6 changed files with 48 additions and 35 deletions
|
@ -577,7 +577,7 @@ void CookieJar::select_all_cookies_from_database(OnSelectAllCookiesResult on_res
|
||||||
promise->resolve({});
|
promise->resolve({});
|
||||||
});
|
});
|
||||||
|
|
||||||
promise->await();
|
MUST(promise->await());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CookieJar::purge_expired_cookies()
|
void CookieJar::purge_expired_cookies()
|
||||||
|
|
|
@ -132,9 +132,9 @@ bool MailWidget::connect_and_login()
|
||||||
|
|
||||||
auto connection_promise = m_imap_client->connection_promise();
|
auto connection_promise = m_imap_client->connection_promise();
|
||||||
VERIFY(!connection_promise.is_null());
|
VERIFY(!connection_promise.is_null());
|
||||||
connection_promise->await();
|
MUST(connection_promise->await());
|
||||||
|
|
||||||
auto response = m_imap_client->login(username, password)->await().release_value();
|
auto response = MUST(m_imap_client->login(username, password)->await()).release_value();
|
||||||
|
|
||||||
if (response.status() != IMAP::ResponseStatus::OK) {
|
if (response.status() != IMAP::ResponseStatus::OK) {
|
||||||
dbgln("Failed to login. The server says: '{}'", response.response_text());
|
dbgln("Failed to login. The server says: '{}'", response.response_text());
|
||||||
|
@ -142,7 +142,7 @@ bool MailWidget::connect_and_login()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
response = m_imap_client->list(""sv, "*"sv)->await().release_value();
|
response = MUST(m_imap_client->list(""sv, "*"sv)->await()).release_value();
|
||||||
|
|
||||||
if (response.status() != IMAP::ResponseStatus::OK) {
|
if (response.status() != IMAP::ResponseStatus::OK) {
|
||||||
dbgln("Failed to retrieve mailboxes. The server says: '{}'", response.response_text());
|
dbgln("Failed to retrieve mailboxes. The server says: '{}'", response.response_text());
|
||||||
|
@ -163,7 +163,7 @@ bool MailWidget::connect_and_login()
|
||||||
|
|
||||||
void MailWidget::on_window_close()
|
void MailWidget::on_window_close()
|
||||||
{
|
{
|
||||||
auto response = move(m_imap_client->send_simple_command(IMAP::CommandType::Logout)->await().release_value().get<IMAP::SolidResponse>());
|
auto response = move(MUST(m_imap_client->send_simple_command(IMAP::CommandType::Logout)->await()).release_value().get<IMAP::SolidResponse>());
|
||||||
VERIFY(response.status() == IMAP::ResponseStatus::OK);
|
VERIFY(response.status() == IMAP::ResponseStatus::OK);
|
||||||
|
|
||||||
m_imap_client->close();
|
m_imap_client->close();
|
||||||
|
@ -253,7 +253,7 @@ void MailWidget::selected_mailbox()
|
||||||
if (mailbox.flags & (unsigned)IMAP::MailboxFlag::NoSelect)
|
if (mailbox.flags & (unsigned)IMAP::MailboxFlag::NoSelect)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto response = m_imap_client->select(mailbox.name)->await().release_value();
|
auto response = MUST(m_imap_client->select(mailbox.name)->await()).release_value();
|
||||||
|
|
||||||
if (response.status() != IMAP::ResponseStatus::OK) {
|
if (response.status() != IMAP::ResponseStatus::OK) {
|
||||||
dbgln("Failed to select mailbox. The server says: '{}'", response.response_text());
|
dbgln("Failed to select mailbox. The server says: '{}'", response.response_text());
|
||||||
|
@ -280,7 +280,7 @@ void MailWidget::selected_mailbox()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
auto fetch_response = m_imap_client->fetch(fetch_command, false)->await().release_value();
|
auto fetch_response = MUST(m_imap_client->fetch(fetch_command, false)->await()).release_value();
|
||||||
|
|
||||||
if (response.status() != IMAP::ResponseStatus::OK) {
|
if (response.status() != IMAP::ResponseStatus::OK) {
|
||||||
dbgln("Failed to retrieve subject/from for e-mails. The server says: '{}'", response.response_text());
|
dbgln("Failed to retrieve subject/from for e-mails. The server says: '{}'", response.response_text());
|
||||||
|
@ -396,7 +396,7 @@ void MailWidget::selected_email_to_load()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
auto fetch_response = m_imap_client->fetch(fetch_command, false)->await().release_value();
|
auto fetch_response = MUST(m_imap_client->fetch(fetch_command, false)->await()).release_value();
|
||||||
|
|
||||||
if (fetch_response.status() != IMAP::ResponseStatus::OK) {
|
if (fetch_response.status() != IMAP::ResponseStatus::OK) {
|
||||||
dbgln("Failed to retrieve the body structure of the selected e-mail. The server says: '{}'", fetch_response.response_text());
|
dbgln("Failed to retrieve the body structure of the selected e-mail. The server says: '{}'", fetch_response.response_text());
|
||||||
|
@ -457,7 +457,7 @@ void MailWidget::selected_email_to_load()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
fetch_response = m_imap_client->fetch(fetch_command, false)->await().release_value();
|
fetch_response = MUST(m_imap_client->fetch(fetch_command, false)->await()).release_value();
|
||||||
|
|
||||||
if (fetch_response.status() != IMAP::ResponseStatus::OK) {
|
if (fetch_response.status() != IMAP::ResponseStatus::OK) {
|
||||||
dbgln("Failed to retrieve the body of the selected e-mail. The server says: '{}'", fetch_response.response_text());
|
dbgln("Failed to retrieve the body of the selected e-mail. The server says: '{}'", fetch_response.response_text());
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <LibCore/Object.h>
|
#include <LibCore/Object.h>
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
template<typename Result>
|
template<typename Result>
|
||||||
class Promise : public Object {
|
class Promise : public Object {
|
||||||
C_OBJECT(Promise);
|
C_OBJECT(Promise);
|
||||||
|
@ -19,22 +20,33 @@ public:
|
||||||
|
|
||||||
void resolve(Result&& result)
|
void resolve(Result&& result)
|
||||||
{
|
{
|
||||||
m_pending = move(result);
|
m_pending_or_error = move(result);
|
||||||
|
|
||||||
if (on_resolved)
|
if (on_resolved)
|
||||||
on_resolved(m_pending.value());
|
on_resolved(m_pending_or_error.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_resolved()
|
void cancel(Error error)
|
||||||
{
|
{
|
||||||
return m_pending.has_value();
|
m_pending_or_error = move(error);
|
||||||
};
|
}
|
||||||
|
|
||||||
Result await()
|
bool is_canceled()
|
||||||
{
|
{
|
||||||
while (!is_resolved()) {
|
return m_pending_or_error.has_value() && m_pending_or_error->is_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_resolved() const
|
||||||
|
{
|
||||||
|
return m_pending_or_error.has_value() && !m_pending_or_error->is_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<Result> await()
|
||||||
|
{
|
||||||
|
while (!m_pending_or_error.has_value())
|
||||||
Core::EventLoop::current().pump();
|
Core::EventLoop::current().pump();
|
||||||
}
|
|
||||||
return m_pending.release_value();
|
return m_pending_or_error.release_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts a Promise<A> to a Promise<B> using a function func: A -> B
|
// Converts a Promise<A> to a Promise<B> using a function func: A -> B
|
||||||
|
@ -52,6 +64,7 @@ public:
|
||||||
private:
|
private:
|
||||||
Promise() = default;
|
Promise() = default;
|
||||||
|
|
||||||
Optional<Result> m_pending;
|
Optional<ErrorOr<Result>> m_pending_or_error;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -170,7 +170,7 @@ int Client::get_new_id()
|
||||||
|
|
||||||
Result Client::handle_promise(int id)
|
Result Client::handle_promise(int id)
|
||||||
{
|
{
|
||||||
auto result = m_promises.get(id)->promise->await();
|
auto result = TRY(m_promises.get(id)->promise->await());
|
||||||
m_promises.remove(id);
|
m_promises.remove(id);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,7 +80,7 @@ ErrorOr<void> Session::start(LaunchBrowserCallbacks const& callbacks)
|
||||||
|
|
||||||
// FIXME: Allow this to be more asynchronous. For now, this at least allows us to propagate
|
// FIXME: Allow this to be more asynchronous. For now, this at least allows us to propagate
|
||||||
// errors received while accepting the Browser and WebContent sockets.
|
// errors received while accepting the Browser and WebContent sockets.
|
||||||
TRY(promise->await());
|
TRY(TRY(promise->await()));
|
||||||
|
|
||||||
m_started = true;
|
m_started = true;
|
||||||
return {};
|
return {};
|
||||||
|
|
|
@ -44,20 +44,20 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||||
|
|
||||||
Core::EventLoop loop;
|
Core::EventLoop loop;
|
||||||
auto client = TRY(tls ? IMAP::Client::connect_tls(host, port) : IMAP::Client::connect_plaintext(host, port));
|
auto client = TRY(tls ? IMAP::Client::connect_tls(host, port) : IMAP::Client::connect_plaintext(host, port));
|
||||||
client->connection_promise()->await();
|
TRY(client->connection_promise()->await());
|
||||||
|
|
||||||
auto response = client->login(username, password.view())->await().release_value();
|
auto response = TRY(client->login(username, password.view())->await()).release_value();
|
||||||
outln("[LOGIN] Login response: {}", response.response_text());
|
outln("[LOGIN] Login response: {}", response.response_text());
|
||||||
|
|
||||||
response = move(client->send_simple_command(IMAP::CommandType::Capability)->await().value().get<IMAP::SolidResponse>());
|
response = move(TRY(client->send_simple_command(IMAP::CommandType::Capability)->await()).value().get<IMAP::SolidResponse>());
|
||||||
outln("[CAPABILITY] First capability: {}", response.data().capabilities().first());
|
outln("[CAPABILITY] First capability: {}", response.data().capabilities().first());
|
||||||
bool idle_supported = !response.data().capabilities().find_if([](auto capability) { return capability.equals_ignoring_ascii_case("IDLE"sv); }).is_end();
|
bool idle_supported = !response.data().capabilities().find_if([](auto capability) { return capability.equals_ignoring_ascii_case("IDLE"sv); }).is_end();
|
||||||
|
|
||||||
response = client->list(""sv, "*"sv)->await().release_value();
|
response = TRY(client->list(""sv, "*"sv)->await()).release_value();
|
||||||
outln("[LIST] First mailbox: {}", response.data().list_items().first().name);
|
outln("[LIST] First mailbox: {}", response.data().list_items().first().name);
|
||||||
|
|
||||||
auto mailbox = "Inbox"sv;
|
auto mailbox = "Inbox"sv;
|
||||||
response = client->select(mailbox)->await().release_value();
|
response = TRY(client->select(mailbox)->await()).release_value();
|
||||||
outln("[SELECT] Select response: {}", response.response_text());
|
outln("[SELECT] Select response: {}", response.response_text());
|
||||||
|
|
||||||
auto message = Message {
|
auto message = Message {
|
||||||
|
@ -71,7 +71,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||||
"So, \"Hello\"."
|
"So, \"Hello\"."
|
||||||
};
|
};
|
||||||
auto promise = client->append("INBOX"sv, move(message));
|
auto promise = client->append("INBOX"sv, move(message));
|
||||||
response = promise->await().release_value();
|
response = TRY(promise->await()).release_value();
|
||||||
outln("[APPEND] Response: {}", response.response_text());
|
outln("[APPEND] Response: {}", response.response_text());
|
||||||
|
|
||||||
Vector<IMAP::SearchKey> keys;
|
Vector<IMAP::SearchKey> keys;
|
||||||
|
@ -79,13 +79,13 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||||
IMAP::SearchKey::From { "jdoe@machine.example" } });
|
IMAP::SearchKey::From { "jdoe@machine.example" } });
|
||||||
keys.append(IMAP::SearchKey {
|
keys.append(IMAP::SearchKey {
|
||||||
IMAP::SearchKey::Subject { "Saying Hello" } });
|
IMAP::SearchKey::Subject { "Saying Hello" } });
|
||||||
response = client->search({}, move(keys), false)->await().release_value();
|
response = TRY(client->search({}, move(keys), false)->await()).release_value();
|
||||||
|
|
||||||
Vector<unsigned> search_results = move(response.data().search_results());
|
Vector<unsigned> search_results = move(response.data().search_results());
|
||||||
auto added_message = search_results.first();
|
auto added_message = search_results.first();
|
||||||
outln("[SEARCH] Number of results: {}", search_results.size());
|
outln("[SEARCH] Number of results: {}", search_results.size());
|
||||||
|
|
||||||
response = client->status("INBOX"sv, { IMAP::StatusItemType::Recent, IMAP::StatusItemType::Messages })->await().release_value();
|
response = TRY(client->status("INBOX"sv, { IMAP::StatusItemType::Recent, IMAP::StatusItemType::Messages })->await()).release_value();
|
||||||
outln("[STATUS] Recent items: {}", response.data().status_item().get(IMAP::StatusItemType::Recent));
|
outln("[STATUS] Recent items: {}", response.data().status_item().get(IMAP::StatusItemType::Recent));
|
||||||
|
|
||||||
for (auto item : search_results) {
|
for (auto item : search_results) {
|
||||||
|
@ -118,7 +118,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
auto fetch_response = client->fetch(fetch_command, false)->await().release_value();
|
auto fetch_response = TRY(client->fetch(fetch_command, false)->await()).release_value();
|
||||||
outln("[FETCH] Subject of search result: {}",
|
outln("[FETCH] Subject of search result: {}",
|
||||||
fetch_response.data()
|
fetch_response.data()
|
||||||
.fetch_data()
|
.fetch_data()
|
||||||
|
@ -136,22 +136,22 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||||
// FIXME: There is a discrepancy between IMAP::Sequence wanting signed ints
|
// FIXME: There is a discrepancy between IMAP::Sequence wanting signed ints
|
||||||
// and IMAP search results returning unsigned ones. Find which one is
|
// and IMAP search results returning unsigned ones. Find which one is
|
||||||
// more correct and fix this.
|
// more correct and fix this.
|
||||||
response = client->store(IMAP::StoreMethod::Add, { static_cast<int>(added_message), static_cast<int>(added_message) }, false, { "\\Deleted" }, false)->await().release_value();
|
response = TRY(client->store(IMAP::StoreMethod::Add, { static_cast<int>(added_message), static_cast<int>(added_message) }, false, { "\\Deleted" }, false)->await()).release_value();
|
||||||
outln("[STORE] Store response: {}", response.response_text());
|
outln("[STORE] Store response: {}", response.response_text());
|
||||||
|
|
||||||
response = move(client->send_simple_command(IMAP::CommandType::Expunge)->await().release_value().get<IMAP::SolidResponse>());
|
response = move(TRY(client->send_simple_command(IMAP::CommandType::Expunge)->await()).release_value().get<IMAP::SolidResponse>());
|
||||||
outln("[EXPUNGE] Number of expunged entries: {}", response.data().expunged().size());
|
outln("[EXPUNGE] Number of expunged entries: {}", response.data().expunged().size());
|
||||||
|
|
||||||
if (idle_supported) {
|
if (idle_supported) {
|
||||||
VERIFY(client->idle()->await().has_value());
|
VERIFY(TRY(client->idle()->await()).has_value());
|
||||||
sleep(3);
|
sleep(3);
|
||||||
response = client->finish_idle()->await().release_value();
|
response = TRY(client->finish_idle()->await()).release_value();
|
||||||
outln("[IDLE] Idle response: {}", response.response_text());
|
outln("[IDLE] Idle response: {}", response.response_text());
|
||||||
} else {
|
} else {
|
||||||
outln("[IDLE] Skipped. No IDLE support.");
|
outln("[IDLE] Skipped. No IDLE support.");
|
||||||
}
|
}
|
||||||
|
|
||||||
response = move(client->send_simple_command(IMAP::CommandType::Logout)->await().release_value().get<IMAP::SolidResponse>());
|
response = move(TRY(client->send_simple_command(IMAP::CommandType::Logout)->await()).release_value().get<IMAP::SolidResponse>());
|
||||||
outln("[LOGOUT] Bye: {}", response.data().bye_message().value());
|
outln("[LOGOUT] Bye: {}", response.data().bye_message().value());
|
||||||
|
|
||||||
client->close();
|
client->close();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue