mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-19 21:37:57 +08:00
fixed cloud console crash error
This commit is contained in:
parent
86b931dfcc
commit
68ffe1f2bd
@ -3995,50 +3995,50 @@
|
||||
"assets/src/ba_data/python/ba/_generated/__init__.py": "https://files.ballistica.net/cache/ba1/ee/e8/cad05aa531c7faf7ff7b96db7f6e",
|
||||
"assets/src/ba_data/python/ba/_generated/enums.py": "https://files.ballistica.net/cache/ba1/b2/e5/0ee0561e16257a32830645239f34",
|
||||
"ballisticacore-windows/Generic/BallisticaCore.ico": "https://files.ballistica.net/cache/ba1/89/c0/e32c7d2a35dc9aef57cc73b0911a",
|
||||
"build/prefab/full/linux_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/bc/d7/f65513a0b3d5fa8b5f4cfe342052",
|
||||
"build/prefab/full/linux_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/06/03/381b1b4470868245225dd4e4bb67",
|
||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/52/b0/36011f65de64a547009bef7fe6ec",
|
||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e2/46/384efcdbfb324b63889d567e7f14",
|
||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/8b/27/7bab35742af8c101f4aab3ebbd3d",
|
||||
"build/prefab/full/linux_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3b/d0/c1ee5a02a09c1d676a22a20fe8a7",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e9/2e/3ae4fb2983bb36167d1fe3044358",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/9e/93/12e8d5357db44c97549fe2fbd7ca",
|
||||
"build/prefab/full/mac_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/53/6d/06e5987cfcf47d740ead2e8c3b7f",
|
||||
"build/prefab/full/mac_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/1b/5b/fd0fa7104c3e2d3a22c180db47cf",
|
||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ca/98/0e12c6aa44fc9e64492b6da67b02",
|
||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e6/81/aacab39968075487c9f610e3036c",
|
||||
"build/prefab/full/mac_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/94/bc/7a2fb10033217cac2fc04ccd0309",
|
||||
"build/prefab/full/mac_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a4/da/b7095762fbdef22aff5d77c5d45d",
|
||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/8b/05/2051b310f7989aa9aa04339de2f3",
|
||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/2d/6e/3befc00833dc482ef55b70a915fe",
|
||||
"build/prefab/full/windows_x86_gui/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/82/ce/77695599588b675fac1e10febeae",
|
||||
"build/prefab/full/windows_x86_gui/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/3a/c3/d042e59d36f71c885036ed0e73d4",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/87/48/b1551cd7b5cf44c06a3e3a1a66a4",
|
||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/6d/e2/3366be4f442e6ef48b5ef5babe87",
|
||||
"build/prefab/lib/linux_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/d6/9a/5e36fb51a797da74db8f366a8e6d",
|
||||
"build/prefab/lib/linux_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/98/d7/e827cc644d4dde0c1bddb17121b0",
|
||||
"build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/9b/e0/a1ae5fdadff116de78727e2a8d30",
|
||||
"build/prefab/lib/linux_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/49/76/fd27d293fd73d324ecc433b1e253",
|
||||
"build/prefab/lib/linux_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/1e/93/b85c7585218b5c86d766a23373c6",
|
||||
"build/prefab/lib/linux_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/34/0a/4547b5a8a00a35874cfbab25fc11",
|
||||
"build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/68/5a/a4a030424d8d5900433bdb70bd83",
|
||||
"build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/e1/4b/278433e2332245313d4fa3390aee",
|
||||
"build/prefab/lib/mac_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/22/c1/fc9726d56ac62c757e7f7eeb56e2",
|
||||
"build/prefab/lib/mac_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/23/4f/ee03bed8d42b8e12832efbd17968",
|
||||
"build/prefab/lib/mac_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/dc/7a/f5bae1a284d2b51e149f12da9e18",
|
||||
"build/prefab/lib/mac_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/2e/75/254680a01a85fcdc19db275cd2ff",
|
||||
"build/prefab/lib/mac_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/79/fb/65e1f1851f2dc663eb5d9dd27ae9",
|
||||
"build/prefab/lib/mac_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/24/5d/33ca757aa471e81ee2efe83b5c32",
|
||||
"build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/83/3e/35613478ab4887b7f77126c1d910",
|
||||
"build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ba/a7/b925b7eb7b2da10fdc9c88e59576",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/0a/ae/daac4e04ef473d0da419ebe2ddf2",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/52/9d/d6c5366d82b56d1c79553ae3258b",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/35/db/9f6868dde4184cb3b33153981548",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/0c/e0/a869977d8ee1dcf4bcbb0853fe3c",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/31/c1/e51379d7cf51aec768855e6e7eb7",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/0f/48/52683efe93f7311f2a81a280a87e",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/7c/05/660a71d76685232d9bd91d979ef8",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/30/5a/b2e0ce3986936938c65e4bef2d0e",
|
||||
"build/prefab/full/linux_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/b3/94/954559711625a0bb6a29d41c35ff",
|
||||
"build/prefab/full/linux_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/44/1e/7eec4d37c0c2afb581927efbb2dc",
|
||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/92/75/2d6b53a09ce1fe7cbe3b50d832de",
|
||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/cf/eb/2f2119b7c86ecbfb2a8b725b21f6",
|
||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/c2/95/be04f3219b078c92a787627b42b7",
|
||||
"build/prefab/full/linux_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/53/f5/3bd3ba9c59b87ff7b8abc4233844",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5e/21/a913309416dde18bc4c9104c3ec5",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/28/25/54314d17a5a12be51a3b340359bd",
|
||||
"build/prefab/full/mac_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/07/39/13923a2f10d8e2a8d1d12007cbed",
|
||||
"build/prefab/full/mac_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a7/86/8cfb723071ad46355af9166ba59a",
|
||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ad/73/6013ee6879fae3c3e06b15396fb0",
|
||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/da/8b/f33a546e2342591ab84ddcf4053e",
|
||||
"build/prefab/full/mac_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f8/b7/fffc4c52e906890b35c936441b60",
|
||||
"build/prefab/full/mac_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/27/24/2ca5005df08ea5a7a78cd20b020a",
|
||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/cd/8d/c59fcc270b637990d12cd8a758e0",
|
||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/54/a9/78e4658fd4446898b11633191c01",
|
||||
"build/prefab/full/windows_x86_gui/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/53/30/cd915e748f31208239b90f5a7a2c",
|
||||
"build/prefab/full/windows_x86_gui/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/a9/4e/c367a7a66eb17df7757dc85d59b6",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/5d/13/38ab5bdd9fdb0abca878d0bbfbab",
|
||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/02/62/c3a8023aa43567204407325d6c4c",
|
||||
"build/prefab/lib/linux_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/23/17/f0d22a9a91a295ee4a9d94db2af9",
|
||||
"build/prefab/lib/linux_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/d5/4f/bfbcdd18679b4ba0df1b040e8c15",
|
||||
"build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/96/e9/0f4aa3d10f2d50fe670bb6d89ba0",
|
||||
"build/prefab/lib/linux_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/26/ef/1b58d3c788441242ed9ca9352499",
|
||||
"build/prefab/lib/linux_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/79/77/b35c5f93f62d92fe9cdb548f6e54",
|
||||
"build/prefab/lib/linux_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/c6/53/8e678b75f456378e17e4f639fe35",
|
||||
"build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ab/1d/b514c16cfda2f5840676a4c75ca3",
|
||||
"build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/d7/c4/b797fd5365d34fcfb60d6275fb3c",
|
||||
"build/prefab/lib/mac_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/b0/6c/b8f8c1d1d8e2f772208af12e085f",
|
||||
"build/prefab/lib/mac_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/c0/e1/f57102a8da2fe0ca7787c0a7924a",
|
||||
"build/prefab/lib/mac_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/8f/16/19494ad899b3f1990dd2b5cdfa99",
|
||||
"build/prefab/lib/mac_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/a9/d5/59ba30f21d5583bdc92516c0916e",
|
||||
"build/prefab/lib/mac_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/e7/82/e29dbff494964b753a08eaa66b66",
|
||||
"build/prefab/lib/mac_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/2f/06/ec124d5bfce4d3f268b1318755b8",
|
||||
"build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/3f/47/3322caea5f9a92735076c1017839",
|
||||
"build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/f5/9f/ce9a27aea9a4b7056800cf68afe9",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/6c/56/6180e5d6db6868b7438751320faf",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/71/24/e873efab9c315ec907427bd22327",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/3d/d6/b1a3c97a66d3f5ad38d5f5dda476",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/5a/e9/14593b84a3035a1bd7ce3980818d",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/87/5c/38b4d59ad04f6ba89dae6ca38fa5",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/3c/0a/6b151c9054294db58cf98957a515",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/e3/fb/7be0f96c82816af61849aaf4357a",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/23/dc/91a8e0f2123a75b4d72a0d26ab25",
|
||||
"src/ballistica/generated/python_embedded/binding.inc": "https://files.ballistica.net/cache/ba1/c0/32/b7907e3859a5c5013a3d97b6b523",
|
||||
"src/ballistica/generated/python_embedded/bootstrap.inc": "https://files.ballistica.net/cache/ba1/2d/4f/f4fe67827f36cd59cd5193333a02",
|
||||
"src/ballistica/generated/python_embedded/bootstrap_monolithic.inc": "https://files.ballistica.net/cache/ba1/ef/c1/aa5f1aa10af89f5c0b1e616355fd"
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
### 1.7.7 (build 20862, api 7, 2022-09-17)
|
||||
### 1.7.7 (build 20865, api 7, 2022-09-19)
|
||||
- Added `ba.app.meta.load_exported_classes()` for loading classes discovered by the meta subsystem cleanly in a background thread.
|
||||
- Improved logging of missing playlist game types.
|
||||
- Some ba.Lstr functionality can now be used in background threads.
|
||||
@ -39,6 +39,8 @@
|
||||
- If you want to grab recent logs, you can now use `ba.app.log_handler.get_cached()`. This will give you everything that has gone through Python logging, Python stdout/stderr, and the C++ Log() call (up to the max cache size that is).
|
||||
- LogHandler output now ALWAYS goes to stderr. Previously it only would if an interactive terminal was detected. This should make the binary easier to debug if run from scripts/etc. We can add a `--quiet` option if needed or whatnot.
|
||||
- (build 20859) Fixed an error setting up asyncio loops under Windows related to the fact that Python is now inited in the main thread.
|
||||
- (build 20864) Fatal-error message/traceback now properly prints to stderr again (I think the reject logging rejiggering caused it to stop).
|
||||
- (build 20864) Fixed an issue where the app could crash when connected to the cloud console while in a network game.
|
||||
|
||||
|
||||
### 1.7.6 (build 20687, api 7, 2022-08-11)
|
||||
|
||||
@ -1 +1 @@
|
||||
84155513838284412598729205538639495871
|
||||
137071025041513581787580065580079045765
|
||||
@ -44,7 +44,7 @@ def bootstrap() -> None:
|
||||
|
||||
# Give a soft warning if we're being used with a different binary
|
||||
# version than we expect.
|
||||
expected_build = 20862
|
||||
expected_build = 20865
|
||||
running_build: int = env['build_number']
|
||||
if running_build != expected_build:
|
||||
print(
|
||||
|
||||
@ -32,7 +32,7 @@
|
||||
namespace ballistica {
|
||||
|
||||
// These are set automatically via script; don't modify them here.
|
||||
const int kAppBuildNumber = 20862;
|
||||
const int kAppBuildNumber = 20865;
|
||||
const char* kAppVersion = "1.7.7";
|
||||
|
||||
// Our standalone globals.
|
||||
|
||||
@ -27,7 +27,7 @@ auto FatalError::ReportFatalError(const std::string& message,
|
||||
// error to the user and exiting the app cleanly (so we don't pollute our
|
||||
// crash records with results of user tinkering).
|
||||
|
||||
// Give the platform the opportunity to completely override our handling.
|
||||
// Give the platform the opportunity to augment or override our handling.
|
||||
if (g_platform) {
|
||||
auto handled =
|
||||
g_platform->ReportFatalError(message, in_top_level_exception_handler);
|
||||
@ -38,7 +38,8 @@ auto FatalError::ReportFatalError(const std::string& message,
|
||||
|
||||
std::string dialog_msg = message;
|
||||
if (!dialog_msg.empty()) {
|
||||
dialog_msg += "\n";
|
||||
// Why was this here?
|
||||
// dialog_msg += "\n";
|
||||
}
|
||||
|
||||
auto starttime = time(nullptr);
|
||||
@ -75,9 +76,10 @@ auto FatalError::ReportFatalError(const std::string& message,
|
||||
g_early_v1_cloud_log_writes = 0;
|
||||
|
||||
// Add this to our V1CloudLog which we'll be attempting to send momentarily,
|
||||
// and also try to present it directly to the user.
|
||||
// and also go to platform-specific logging and good ol' stderr.
|
||||
Logging::V1CloudLog(logmsg);
|
||||
Logging::DisplayLog("root", LogLevel::kCritical, logmsg);
|
||||
fprintf(stderr, "%s\n", logmsg.c_str());
|
||||
|
||||
std::string prefix = "FATAL-ERROR-LOG:";
|
||||
std::string suffix;
|
||||
|
||||
@ -1050,15 +1050,10 @@ void Logic::PushPythonRawCallable(PyObject* callable, bool fg_context) {
|
||||
thread()->PushCall([this, callable, fg_context] {
|
||||
assert(InLogicThread());
|
||||
|
||||
// Lets run this in the UI context.
|
||||
// (can add other options if we need later)
|
||||
// Run this in the UI context by default, or foreground if requested.
|
||||
ScopedSetContext cp(fg_context ? GetForegroundContext() : GetUIContext());
|
||||
|
||||
// This event contains a raw python obj with an incremented ref-count.
|
||||
auto call(Object::New<PythonContextCall>(callable));
|
||||
Py_DECREF(callable); // now just held by call
|
||||
|
||||
call->Run();
|
||||
PythonRef(callable, PythonRef::kSteal).Call();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -83,8 +83,8 @@ class Logic {
|
||||
auto PushPythonWeakCallArgs(const Object::WeakRef<PythonContextCall>& call,
|
||||
const PythonRef& args) -> void;
|
||||
|
||||
// Push a raw Python call, decrements its refcount after running.
|
||||
// Can be pushed from any thread.
|
||||
// Push a raw Python call from any thread. Refcount should be incremented
|
||||
// beforehand and will be decremented after running.
|
||||
auto PushPythonRawCallable(PyObject* callable, bool fg_context = false)
|
||||
-> void;
|
||||
auto PushScreenMessage(const std::string& message, const Vector3f& color)
|
||||
|
||||
@ -102,7 +102,7 @@ auto PythonClassContextCall::tp_new(PyTypeObject* type, PyObject* args,
|
||||
if (!PyArg_ParseTuple(args, "O", &source_obj)) return nullptr;
|
||||
if (!InLogicThread()) {
|
||||
throw Exception(
|
||||
"ERROR: " + std::string(type_obj.tp_name)
|
||||
std::string(type_obj.tp_name)
|
||||
+ " objects must only be created in the logic thread (current is ("
|
||||
+ GetCurrentThreadName() + ").");
|
||||
}
|
||||
|
||||
@ -14,17 +14,17 @@ PythonContextCall* PythonContextCall::current_call_ = nullptr;
|
||||
|
||||
PythonContextCall::PythonContextCall(PyObject* obj_in) {
|
||||
assert(InLogicThread());
|
||||
// as a sanity test, store the current context ptr just to make sure it
|
||||
// hasn't changed when we run
|
||||
// As a sanity test, store the current context ptr just to make sure it
|
||||
// hasn't changed when we run.
|
||||
#if BA_DEBUG_BUILD
|
||||
context_target_sanity_test_ = context_.target.get();
|
||||
#endif // BA_DEBUG_BUILD
|
||||
BA_PRECONDITION(PyCallable_Check(obj_in));
|
||||
object_.Acquire(obj_in);
|
||||
GetTrace();
|
||||
// ok now we need to register this call with whatever the context is;
|
||||
// Ok now we need to register this call with whatever the context is;
|
||||
// it can be stored in a host-activity, a host-session, or the UI context.
|
||||
// whoever it is registered with will explicitly release its contents on
|
||||
// Whoever it is registered with will explicitly release its contents on
|
||||
// shutdown and ensure that nothing gets run after that point.
|
||||
if (HostActivity* ha = context_.GetHostActivity()) {
|
||||
ha->RegisterCall(this);
|
||||
|
||||
@ -18,7 +18,7 @@ from efro.dataclassio import ioprepped
|
||||
from efro.message import (Message, Response, MessageProtocol, MessageSender,
|
||||
BoundMessageSender, MessageReceiver,
|
||||
BoundMessageReceiver, UnregisteredMessageIDError,
|
||||
EmptyResponse)
|
||||
EmptySysResponse)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Callable, Awaitable
|
||||
@ -424,8 +424,8 @@ TEST_PROTOCOL = MessageProtocol(
|
||||
0: _TResp1,
|
||||
1: _TResp2,
|
||||
},
|
||||
receiver_returns_stack_traces=True,
|
||||
receiver_logs_exceptions=False,
|
||||
forward_clean_errors=True,
|
||||
remote_errors_include_stack_traces=True,
|
||||
)
|
||||
|
||||
# Represents an 'evolved' TEST_PROTOCOL (one extra message type added).
|
||||
@ -441,8 +441,8 @@ TEST_PROTOCOL_B = MessageProtocol(
|
||||
0: _TResp1,
|
||||
1: _TResp2,
|
||||
},
|
||||
receiver_returns_stack_traces=True,
|
||||
receiver_logs_exceptions=False,
|
||||
forward_clean_errors=True,
|
||||
remote_errors_include_stack_traces=True,
|
||||
)
|
||||
|
||||
TEST_PROTOCOL_SINGLE = MessageProtocol(
|
||||
@ -452,8 +452,7 @@ TEST_PROTOCOL_SINGLE = MessageProtocol(
|
||||
response_types={
|
||||
0: _TResp1,
|
||||
},
|
||||
receiver_returns_stack_traces=True,
|
||||
receiver_logs_exceptions=False,
|
||||
remote_errors_include_stack_traces=True,
|
||||
)
|
||||
|
||||
|
||||
@ -463,12 +462,16 @@ def test_protocol_creation() -> None:
|
||||
# This should fail because _TMsg1 can return _TResp1 which
|
||||
# is not given an id here.
|
||||
with pytest.raises(ValueError):
|
||||
_protocol = MessageProtocol(message_types={0: _TMsg1},
|
||||
response_types={0: _TResp2})
|
||||
_protocol = MessageProtocol(
|
||||
message_types={0: _TMsg1},
|
||||
response_types={0: _TResp2},
|
||||
)
|
||||
|
||||
# Now it should work.
|
||||
_protocol = MessageProtocol(message_types={0: _TMsg1},
|
||||
response_types={0: _TResp1})
|
||||
_protocol = MessageProtocol(
|
||||
message_types={0: _TMsg1},
|
||||
response_types={0: _TResp1},
|
||||
)
|
||||
|
||||
|
||||
def test_sender_module_single_emb() -> None:
|
||||
@ -777,7 +780,7 @@ def test_full_pipeline() -> None:
|
||||
# Emulate forwarding unregistered messages on to some
|
||||
# other handler...
|
||||
response_dict = self.msg.protocol.response_to_dict(
|
||||
EmptyResponse())
|
||||
EmptySysResponse())
|
||||
return self.msg.protocol.encode_dict(response_dict)
|
||||
raise
|
||||
|
||||
@ -909,7 +912,8 @@ def test_full_pipeline() -> None:
|
||||
assert response3 is None
|
||||
assert isinstance(response4, _TResp1)
|
||||
|
||||
# Remote CleanErrors should come across locally as the same.
|
||||
# Remote CleanErrors should come across locally as the same
|
||||
# (provided our protocol has enabled support for them).
|
||||
try:
|
||||
_response5 = obj.msg.send(_TMsg1(ival=1))
|
||||
except Exception as exc:
|
||||
|
||||
@ -11,15 +11,16 @@ from efro.message._protocol import MessageProtocol
|
||||
from efro.message._sender import (MessageSender, BoundMessageSender)
|
||||
from efro.message._receiver import (MessageReceiver, BoundMessageReceiver)
|
||||
from efro.message._module import (create_sender_module, create_receiver_module)
|
||||
from efro.message._message import (Message, Response, EmptyResponse,
|
||||
ErrorResponse, StringResponse, BoolResponse,
|
||||
UnregisteredMessageIDError)
|
||||
from efro.message._message import (Message, Response, EmptySysResponse,
|
||||
ErrorSysResponse, StringResponse,
|
||||
BoolResponse, UnregisteredMessageIDError)
|
||||
|
||||
__all__ = [
|
||||
'Message', 'Response', 'EmptyResponse', 'ErrorResponse', 'StringResponse',
|
||||
'BoolResponse', 'MessageProtocol', 'MessageSender', 'BoundMessageSender',
|
||||
'MessageReceiver', 'BoundMessageReceiver', 'create_sender_module',
|
||||
'create_receiver_module', 'UnregisteredMessageIDError'
|
||||
'Message', 'Response', 'EmptySysResponse', 'ErrorSysResponse',
|
||||
'StringResponse', 'BoolResponse', 'MessageProtocol', 'MessageSender',
|
||||
'BoundMessageSender', 'MessageReceiver', 'BoundMessageReceiver',
|
||||
'create_sender_module', 'create_receiver_module',
|
||||
'UnregisteredMessageIDError'
|
||||
]
|
||||
|
||||
# Have these things present themselves cleanly as 'thismodule.SomeClass'
|
||||
|
||||
@ -27,12 +27,12 @@ class Message:
|
||||
def get_response_types(cls) -> list[type[Response]]:
|
||||
"""Return all message types this Message can result in when sent.
|
||||
|
||||
The default implementation specifies EmptyResponse, so messages with
|
||||
The default implementation specifies EmptySysResponse, so messages with
|
||||
no particular response needs can leave this untouched.
|
||||
Note that ErrorMessage is handled as a special case and does not
|
||||
need to be specified here.
|
||||
"""
|
||||
return [EmptyResponse]
|
||||
return [EmptySysResponse]
|
||||
|
||||
|
||||
class Response:
|
||||
@ -44,7 +44,7 @@ class Response:
|
||||
|
||||
@ioprepped
|
||||
@dataclass
|
||||
class ErrorResponse(Response):
|
||||
class ErrorSysResponse(Response):
|
||||
"""Response saying some error has occurred for the send.
|
||||
|
||||
This type is unique in that it is not returned to the user; it
|
||||
@ -64,12 +64,12 @@ class ErrorResponse(Response):
|
||||
|
||||
@ioprepped
|
||||
@dataclass
|
||||
class EmptyResponse(Response):
|
||||
class EmptySysResponse(Response):
|
||||
"""The response equivalent of None."""
|
||||
|
||||
|
||||
# TODO: could allow handlers to deal in raw values for these
|
||||
# types similar to how we allow None in place of EmptyResponse.
|
||||
# types similar to how we allow None in place of EmptySysResponse.
|
||||
# Though not sure if they are widely used enough to warrant the
|
||||
# extra code complexity.
|
||||
@ioprepped
|
||||
|
||||
@ -14,8 +14,9 @@ import json
|
||||
from efro.error import CleanError
|
||||
from efro.dataclassio import (is_ioprepped_dataclass, dataclass_to_dict,
|
||||
dataclass_from_dict)
|
||||
from efro.message._message import (Message, Response, ErrorResponse,
|
||||
EmptyResponse, UnregisteredMessageIDError)
|
||||
from efro.message._message import (Message, Response, ErrorSysResponse,
|
||||
EmptySysResponse,
|
||||
UnregisteredMessageIDError)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Literal
|
||||
@ -33,29 +34,20 @@ class MessageProtocol:
|
||||
def __init__(self,
|
||||
message_types: dict[int, type[Message]],
|
||||
response_types: dict[int, type[Response]],
|
||||
preserve_clean_errors: bool = True,
|
||||
receiver_logs_exceptions: bool = True,
|
||||
receiver_returns_stack_traces: bool = False) -> None:
|
||||
forward_clean_errors: bool = False,
|
||||
remote_errors_include_stack_traces: bool = False) -> None:
|
||||
"""Create a protocol with a given configuration.
|
||||
|
||||
Note that common response types are automatically registered
|
||||
with (unchanging negative ids) so they don't need to be passed
|
||||
explicitly (but can be if a different id is desired).
|
||||
|
||||
If 'preserve_clean_errors' is True, efro.error.CleanError
|
||||
If 'forward_clean_errors' is True, efro.error.CleanError
|
||||
exceptions raised on the receiver end will result in a matching
|
||||
CleanError raised back on the sender. All other Exception types
|
||||
come across as efro.error.RemoteError.
|
||||
|
||||
When 'receiver_logs_exceptions' is True, any uncaught Exceptions
|
||||
on the receiver end will be logged there via logging.exception()
|
||||
(in addition to the usual behavior of returning an ErrorResponse
|
||||
to the sender). This is good to leave enabled if your
|
||||
intention is to never return ErrorResponses. Looser setups
|
||||
making routine use of CleanErrors or whatnot may want to
|
||||
disable this, however.
|
||||
|
||||
If 'receiver_returns_stack_traces' is True, stringified stack
|
||||
If 'remote_errors_include_stack_traces' is True, stringified stack
|
||||
traces will be returned to the sender for exceptions occurring
|
||||
on the receiver end. This can make debugging easier but should
|
||||
only be used when the client is trusted to see such info.
|
||||
@ -88,15 +80,20 @@ class MessageProtocol:
|
||||
# Go ahead and auto-register a few common response types
|
||||
# if the user has not done so explicitly. Use unique negative
|
||||
# IDs which will never change or overlap with user ids.
|
||||
def _reg_if_not(reg_tp: type[Response], reg_id: int) -> None:
|
||||
def _reg_sys(reg_tp: type[Response], reg_id: int) -> None:
|
||||
|
||||
# If we have a positive id registered already, we still point
|
||||
# negative sys id at this type but not the opposite.
|
||||
if reg_tp in self.response_ids_by_type:
|
||||
self.response_types_by_id[reg_id] = reg_tp
|
||||
return
|
||||
|
||||
assert self.response_types_by_id.get(reg_id) is None
|
||||
self.response_types_by_id[reg_id] = reg_tp
|
||||
self.response_ids_by_type[reg_tp] = reg_id
|
||||
|
||||
_reg_if_not(ErrorResponse, -1)
|
||||
_reg_if_not(EmptyResponse, -2)
|
||||
_reg_sys(ErrorSysResponse, -1)
|
||||
_reg_sys(EmptySysResponse, -2)
|
||||
|
||||
# Some extra-thorough validation in debug mode.
|
||||
if __debug__:
|
||||
@ -127,9 +124,9 @@ class MessageProtocol:
|
||||
'message_types contains duplicate __name__s;'
|
||||
' all types are required to have unique names.')
|
||||
|
||||
self.preserve_clean_errors = preserve_clean_errors
|
||||
self.receiver_logs_exceptions = receiver_logs_exceptions
|
||||
self.receiver_returns_stack_traces = receiver_returns_stack_traces
|
||||
self.forward_clean_errors = forward_clean_errors
|
||||
self.remote_errors_include_stack_traces = (
|
||||
remote_errors_include_stack_traces)
|
||||
|
||||
@staticmethod
|
||||
def encode_dict(obj: dict) -> str:
|
||||
@ -147,21 +144,20 @@ class MessageProtocol:
|
||||
def error_to_response(self, exc: Exception) -> Response:
|
||||
"""Translate an error to a response."""
|
||||
|
||||
# Log any errors we got during handling if so desired.
|
||||
if self.receiver_logs_exceptions:
|
||||
logging.exception('Error in efro.message handling.')
|
||||
# Log any errors we got during handling.
|
||||
logging.exception('Error in efro.message handling.')
|
||||
|
||||
# If anything goes wrong, return a ErrorResponse instead.
|
||||
# If anything goes wrong, return a ErrorSysResponse instead.
|
||||
# (either CLEAN or generic REMOTE)
|
||||
if isinstance(exc, CleanError) and self.preserve_clean_errors:
|
||||
return ErrorResponse(
|
||||
if isinstance(exc, CleanError) and self.forward_clean_errors:
|
||||
return ErrorSysResponse(
|
||||
error_message=str(exc),
|
||||
error_type=ErrorResponse.ErrorType.REMOTE_CLEAN)
|
||||
return ErrorResponse(
|
||||
error_type=ErrorSysResponse.ErrorType.REMOTE_CLEAN)
|
||||
return ErrorSysResponse(
|
||||
error_message=(traceback.format_exc()
|
||||
if self.receiver_returns_stack_traces else
|
||||
if self.remote_errors_include_stack_traces else
|
||||
'An internal error has occurred.'),
|
||||
error_type=ErrorResponse.ErrorType.REMOTE)
|
||||
error_type=ErrorSysResponse.ErrorType.REMOTE)
|
||||
|
||||
def _to_dict(self, message: Any, ids_by_type: dict[type, int],
|
||||
opname: str) -> dict:
|
||||
@ -236,7 +232,7 @@ class MessageProtocol:
|
||||
rsptypes.append(Response)
|
||||
for rsp_tp in rsptypes:
|
||||
# Skip these as they don't actually show up in code.
|
||||
if rsp_tp is EmptyResponse or rsp_tp is ErrorResponse:
|
||||
if rsp_tp is EmptySysResponse or rsp_tp is ErrorSysResponse:
|
||||
continue
|
||||
if (single_message_type and part == 'sender'
|
||||
and rsp_tp is not Response):
|
||||
@ -344,9 +340,9 @@ class MessageProtocol:
|
||||
f' """Protocol-specific bound sender."""\n')
|
||||
|
||||
def _filt_tp_name(rtype: type[Response]) -> str:
|
||||
# We accept None to equal EmptyResponse so reflect that
|
||||
# We accept None to equal EmptySysResponse so reflect that
|
||||
# in the type annotation.
|
||||
return 'None' if rtype is EmptyResponse else rtype.__name__
|
||||
return 'None' if rtype is EmptySysResponse else rtype.__name__
|
||||
|
||||
# Define handler() overloads for all registered message types.
|
||||
if msgtypes:
|
||||
@ -441,9 +437,9 @@ class MessageProtocol:
|
||||
# Define handler() overloads for all registered message types.
|
||||
|
||||
def _filt_tp_name(rtype: type[Response]) -> str:
|
||||
# We accept None to equal EmptyResponse so reflect that
|
||||
# We accept None to equal EmptySysResponse so reflect that
|
||||
# in the type annotation.
|
||||
return 'None' if rtype is EmptyResponse else rtype.__name__
|
||||
return 'None' if rtype is EmptySysResponse else rtype.__name__
|
||||
|
||||
if msgtypes:
|
||||
cbgn = 'Awaitable[' if is_async else ''
|
||||
|
||||
@ -11,8 +11,9 @@ import inspect
|
||||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from efro.message._message import (Message, Response, EmptyResponse,
|
||||
ErrorResponse, UnregisteredMessageIDError)
|
||||
from efro.message._message import (Message, Response, EmptySysResponse,
|
||||
ErrorSysResponse,
|
||||
UnregisteredMessageIDError)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Callable, Awaitable
|
||||
@ -123,8 +124,8 @@ class MessageReceiver:
|
||||
# types.UnionType above.
|
||||
responsetypes = (ret, ) # type: ignore
|
||||
|
||||
# Return type of None translates to EmptyResponse.
|
||||
responsetypes = tuple(EmptyResponse if r is type(None) else r
|
||||
# Return type of None translates to EmptySysResponse.
|
||||
responsetypes = tuple(EmptySysResponse if r is type(None) else r
|
||||
for r in responsetypes) # noqa
|
||||
|
||||
# Make sure our protocol has this message type registered and our
|
||||
@ -236,13 +237,13 @@ class MessageReceiver:
|
||||
response: Response | None) -> str:
|
||||
"""Encode a response provided by the user for sending."""
|
||||
|
||||
# A return value of None equals EmptyResponse.
|
||||
# A return value of None equals EmptySysResponse.
|
||||
if response is None:
|
||||
response = EmptyResponse()
|
||||
response = EmptySysResponse()
|
||||
|
||||
assert isinstance(response, Response)
|
||||
# (user should never explicitly return error-responses)
|
||||
assert not isinstance(response, ErrorResponse)
|
||||
assert not isinstance(response, ErrorSysResponse)
|
||||
assert type(response) in message.get_response_types()
|
||||
response_dict = self.protocol.response_to_dict(response)
|
||||
if self._encode_filter_call is not None:
|
||||
|
||||
@ -10,7 +10,7 @@ import logging
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from efro.error import CleanError, RemoteError, CommunicationError
|
||||
from efro.message._message import EmptyResponse, ErrorResponse
|
||||
from efro.message._message import EmptySysResponse, ErrorSysResponse
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Callable, Awaitable
|
||||
@ -139,12 +139,12 @@ class MessageSender:
|
||||
except Exception as exc:
|
||||
# Any error in the raw send call gets recorded as either
|
||||
# a local or communication error.
|
||||
return ErrorResponse(
|
||||
return ErrorSysResponse(
|
||||
error_message=
|
||||
f'Error in MessageSender @send_method ({type(exc)}): {exc}',
|
||||
error_type=(ErrorResponse.ErrorType.COMMUNICATION
|
||||
error_type=(ErrorSysResponse.ErrorType.COMMUNICATION
|
||||
if isinstance(exc, CommunicationError) else
|
||||
ErrorResponse.ErrorType.LOCAL))
|
||||
ErrorSysResponse.ErrorType.LOCAL))
|
||||
return self._decode_raw_response(bound_obj, message, response_encoded)
|
||||
|
||||
async def send_split_part_1_async(self, bound_obj: Any,
|
||||
@ -166,13 +166,13 @@ class MessageSender:
|
||||
except Exception as exc:
|
||||
# Any error in the raw send call gets recorded as either
|
||||
# a local or communication error.
|
||||
return ErrorResponse(
|
||||
return ErrorSysResponse(
|
||||
error_message=
|
||||
f'Error in MessageSender @send_async_method ({type(exc)}):'
|
||||
f' {exc}',
|
||||
error_type=(ErrorResponse.ErrorType.COMMUNICATION
|
||||
error_type=(ErrorSysResponse.ErrorType.COMMUNICATION
|
||||
if isinstance(exc, CommunicationError) else
|
||||
ErrorResponse.ErrorType.LOCAL))
|
||||
ErrorSysResponse.ErrorType.LOCAL))
|
||||
return self._decode_raw_response(bound_obj, message, response_encoded)
|
||||
|
||||
def send_split_part_2(self, message: Message,
|
||||
@ -214,13 +214,13 @@ class MessageSender:
|
||||
# If we got to this point, we successfully communicated
|
||||
# with the other end so errors represent protocol mismatches
|
||||
# or other invalid data. For now let's just log it but perhaps
|
||||
# we'd want to somehow embed it in the ErrorResponse to be
|
||||
# we'd want to somehow embed it in the ErrorSysResponse to be
|
||||
# available directly to the user later.
|
||||
logging.exception('Error decoding raw response')
|
||||
response = ErrorResponse(
|
||||
response = ErrorSysResponse(
|
||||
error_message=
|
||||
'Error decoding raw response; see log for details.',
|
||||
error_type=ErrorResponse.ErrorType.LOCAL)
|
||||
error_type=ErrorSysResponse.ErrorType.LOCAL)
|
||||
return response
|
||||
|
||||
def _unpack_raw_response(self, raw_response: Response) -> Response | None:
|
||||
@ -232,25 +232,25 @@ class MessageSender:
|
||||
run such that any raised Exception is active when the callback
|
||||
fires; not on the thread where the message was sent.
|
||||
"""
|
||||
# EmptyResponse translates to None
|
||||
if isinstance(raw_response, EmptyResponse):
|
||||
# EmptySysResponse translates to None
|
||||
if isinstance(raw_response, EmptySysResponse):
|
||||
return None
|
||||
|
||||
# Some error occurred. Raise a local Exception for it.
|
||||
if isinstance(raw_response, ErrorResponse):
|
||||
if isinstance(raw_response, ErrorSysResponse):
|
||||
|
||||
if (raw_response.error_type is
|
||||
ErrorResponse.ErrorType.COMMUNICATION):
|
||||
ErrorSysResponse.ErrorType.COMMUNICATION):
|
||||
raise CommunicationError(raw_response.error_message)
|
||||
|
||||
# If something went wrong on *our* end of the connection,
|
||||
# don't say it was a remote error.
|
||||
if raw_response.error_type is ErrorResponse.ErrorType.LOCAL:
|
||||
if raw_response.error_type is ErrorSysResponse.ErrorType.LOCAL:
|
||||
raise RuntimeError(raw_response.error_message)
|
||||
|
||||
# If they want to support clean errors, do those.
|
||||
if (self.protocol.preserve_clean_errors and raw_response.error_type
|
||||
is ErrorResponse.ErrorType.REMOTE_CLEAN):
|
||||
if (self.protocol.forward_clean_errors and raw_response.error_type
|
||||
is ErrorSysResponse.ErrorType.REMOTE_CLEAN):
|
||||
raise CleanError(raw_response.error_message)
|
||||
|
||||
# Everything else gets lumped in as a remote error.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user