-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
I'm sorry for this PR being so big. I took a top-down approach in attempt to let the commits tell a story about how we are approaching this refactoring. Or should I say rewrite instead? Anyways, there are more commits than files touched. It's better reviewed in a commit-by-commit fashion, in my opinion. I had to do it three times to get the storytelling right. I hope it helps. This focus on the Flutter side. It is more complicated than the agent side, IMHO. [The second commit](d2fe835) is the key. All the rest is either making it possible or adapting to the changes introduced to make it possible. (Well, except for the first, which is just a QoL thing - I hate when GitHub flags me because a missing newline at EOF). The essence is: we are hiding WinRT types (including the coroutines) from the MS Store API wrappers, except in the very bottom and very top layers, which can afford being Windows-specific. Since the purchase request must be initiated in the main UI thread and yet must be non-blocking, we leverage the `IAsyncOperation::Completed()` method to supply a completion handler callback to deal with the result and report back to the Flutter land whether the operation succeeded or not. That's the only operation that will remain asynchronous. The rest is progressively being turned into synchronous, blocking API, such as fetching a product. That required splitting the act of fetching the product (which, due being a blocking call must be called in a background thread) from the acting of purchasing. That split motivated me to hide the method `Product::PromptUserForPurchase` and re-expose it in a child class only acessible from the `ClientStoreService` class, which is intended to be used in GUI only. This way it's harder to attempt to call such method without having a parent window to render the native dialogs on top of. The next PR will build on top of this to complete removing the coroutines and hiding the WinRT on the part of the code that is relevant to the agent. NOTE: Git didn't handle well the file renaming on the pair `base/Context.[ch]pp` into `base/impl/StoreContext.[ch]pp`. That renaming is to reinforce that it's one implementation, others will come (talking to the store mock on Windows and on Linux). Talking about mock implementations, I left an easter egg: This is how we'll select production vs mock API (when we implement it): ![image](https://github.com/canonical/ubuntu-pro-for-windows/assets/11138291/415446f0-d257-4806-857a-a02f73f1ae1b) CMake detects that environment variable when building the Flutter app and selects the appropriate sources and also set the preprocessor macro with the same name. [See the third commit](d2fe835) for the details. That trick is even more transparent on MSBuild (I believe that will be needed to build the `storeapi.dll`). Essentially, environment variables are valid MSBuild properties. [See the MSBuild docs](https://learn.microsoft.com/en-us/visualstudio/msbuild/how-to-use-environment-variables-in-a-build?view=vs-2022#reference-environment-variables) for the details. But let's leave that for later. We are still two steps behind building with mocks.
- Loading branch information
Showing
20 changed files
with
462 additions
and
286 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
BasedOnStyle: Google | ||
--- | ||
Language: Cpp | ||
AllowShortFunctionsOnASingleLine: All | ||
DerivePointerAlignment: false | ||
InsertNewlineAtEOF: true | ||
PointerAlignment: Left |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
48 changes: 33 additions & 15 deletions
48
gui/packages/p4w_ms_store/windows/p4w_ms_store_plugin_impl.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,44 @@ | ||
#include "p4w_ms_store_plugin_impl.h" | ||
|
||
#include <flutter/encodable_value.h> | ||
|
||
#include <base/DefaultContext.hpp> | ||
#include <base/Exception.hpp> | ||
#include <base/Purchase.hpp> | ||
#include <gui/ClientStoreService.hpp> | ||
|
||
#include <cstdint> | ||
#include <exception> | ||
|
||
namespace p4w_ms_store { | ||
|
||
winrt::fire_and_forget PurchaseSubscription( | ||
HWND topLevelWindow, std::string productId, | ||
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) { | ||
try { | ||
StoreApi::ClientStoreService service{topLevelWindow}; | ||
const auto res = | ||
co_await service.PromptUserToSubscribe(std::move(productId)); | ||
result->Success(static_cast<int>(res)); | ||
} catch (StoreApi::Exception& err) { | ||
result->Error(channelName, err.what()); | ||
} catch (winrt::hresult_error& err) { | ||
result->Error(channelName, winrt::to_string(err.message())); | ||
} catch (std::exception& err) { | ||
result->Error(channelName, err.what()); | ||
} | ||
std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>> | ||
result) try { | ||
winrt::apartment_context windowContext{}; | ||
StoreApi::ClientStoreService service{topLevelWindow}; | ||
// Blocks a background thread while retrieving the product. | ||
co_await winrt::resume_background(); | ||
const auto product = service.FetchAvailableProduct(productId); | ||
// Resumes in the UI thread to display the native dialog. | ||
co_await windowContext; | ||
product.PromptUserForPurchase( | ||
[result](StoreApi::PurchaseStatus status, int32_t error) { | ||
if (error < 0) { | ||
winrt::hresult_error err{error}; | ||
result->Error(channelName, winrt::to_string(err.message())); | ||
return; | ||
} | ||
|
||
result->Success(static_cast<int>(status)); | ||
}); | ||
} catch (StoreApi::Exception& err) { | ||
result->Error(channelName, err.what()); | ||
} catch (winrt::hresult_error& err) { | ||
result->Error(channelName, winrt::to_string(err.message())); | ||
} catch (std::exception& err) { | ||
result->Error(channelName, err.what()); | ||
} catch (...) { | ||
result->Error(channelName, "Unknown exception thrown in the native layer."); | ||
} | ||
|
||
} // namespace p4w_ms_store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
#pragma once | ||
|
||
#include "impl/StoreContext.hpp" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
#pragma once | ||
|
||
/// Types and aliases that must be present in all Context implementations. | ||
|
||
#include <cstdint> | ||
#include <functional> | ||
|
||
namespace StoreApi { | ||
// We'll certainly want to show in the UI the result of the purchase operation | ||
// in a localizable way. Thus we must agree on the values returned across the | ||
// different languages involved. Since we don't control the Windows Runtime | ||
// APIs, it wouldn't be future-proof to return the raw value of | ||
// StorePurchaseStatus enum right away. | ||
// This must strictly in sync the Dart PurchaseStatus enum in | ||
// https://github.com/canonical/ubuntu-pro-for-windows/blob/main/gui/packages/p4w_ms_store/lib/p4w_ms_store_platform_interface.dart#L8-L16 | ||
// so we don't misinterpret the native call return values. | ||
enum class PurchaseStatus : std::int8_t { | ||
Succeeded = 0, | ||
AlreadyPurchased = 1, | ||
UserGaveUp = 2, | ||
NetworkError = 3, | ||
ServerError = 4, | ||
Unknown = 5, | ||
}; | ||
|
||
/// A callable the client application must provide to receive the result of the | ||
/// asynchronous purchase operation. | ||
using PurchaseCallback = std::function<void(PurchaseStatus, std::int32_t)>; | ||
|
||
} // namespace StoreApi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.