Skip to content

Commit

Permalink
latest server work
Browse files Browse the repository at this point in the history
  • Loading branch information
efroemling committed Nov 20, 2024
1 parent d9024b9 commit 33e6893
Show file tree
Hide file tree
Showing 9 changed files with 221 additions and 54 deletions.
74 changes: 37 additions & 37 deletions .efrocachemap

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
### 1.7.37 (build 22102, api 9, 2024-11-14)
### 1.7.37 (build 22103, api 9, 2024-11-19)
- Bumping api version to 9. As you'll see below, there's some UI changes that
will require a bit of work for any UI mods to adapt to. If your mods don't
touch UI stuff at all you can simply bump your api version and call it a day.
Expand Down
11 changes: 6 additions & 5 deletions src/assets/ba_data/python/baclassic/_appmode.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,20 +157,21 @@ def update_for_primary_account(
"""Update subscriptions/etc. for a new primary account state."""
assert in_logic_thread()

if bool(True):
# Test subscription.
if bool(False):
assert app.plus is not None
if account is None:
self._test_sub = None
else:
with account:
self._test_sub = app.plus.cloud.subscribe(
self._on_sub_update
self._test_sub = app.plus.cloud.subscribe_test(
self._on_sub_test_update
)
else:
self._test_sub = None

def _on_sub_update(self, val: Any) -> None:
print(f'GOT SUB UPDATE: {val}')
def _on_sub_test_update(self, val: int | None) -> None:
print(f'GOT SUB TEST UPDATE: {val}')

def _root_ui_menu_press(self) -> None:
from babase import push_back_press
Expand Down
2 changes: 1 addition & 1 deletion src/assets/ba_data/python/baenv.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@

# Build number and version of the ballistica binary we expect to be
# using.
TARGET_BALLISTICA_BUILD = 22102
TARGET_BALLISTICA_BUILD = 22103
TARGET_BALLISTICA_VERSION = '1.7.37'


Expand Down
26 changes: 23 additions & 3 deletions src/assets/ba_data/python/baplus/_cloud.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from __future__ import annotations

import logging
from functools import partial
from typing import TYPE_CHECKING, overload

import babase
Expand Down Expand Up @@ -174,13 +175,32 @@ async def send_message_async(self, msg: Message) -> Response | None:
'Cloud functionality is not present in this build.'
)

def subscribe(
self, updatecall: Callable[[Any], None]
def subscribe_test(
self, updatecall: Callable[[int | None], None]
) -> babase.CloudSubscription:
"""Subscribe to some data."""
from bacommon.cloud import TestCloudSubscriptionRequest

return self._subscribe(TestCloudSubscriptionRequest(), updatecall)
assert babase.in_logic_thread()

return self._subscribe(
TestCloudSubscriptionRequest(),
partial(self._on_sub_value_test, updatecall),
)

@staticmethod
def _on_sub_value_test(
cb: Callable[[int | None], None],
invalue: bacommon.cloud.CloudSubscriptionValue,
) -> None:
from bacommon.cloud import TestCloudSubscriptionValue

assert babase.in_logic_thread()

# Make sure we got the type we expected for this sub and pass it
# to the user callback.
assert isinstance(invalue, TestCloudSubscriptionValue)
cb(invalue.value)

def _subscribe(
self,
Expand Down
2 changes: 1 addition & 1 deletion src/ballistica/shared/ballistica.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ auto main(int argc, char** argv) -> int {
namespace ballistica {

// These are set automatically via script; don't modify them here.
const int kEngineBuildNumber = 22102;
const int kEngineBuildNumber = 22103;
const char* kEngineVersion = "1.7.37";
const int kEngineApiVersion = 9;

Expand Down
48 changes: 48 additions & 0 deletions tools/bacommon/cloud.py
Original file line number Diff line number Diff line change
Expand Up @@ -369,3 +369,51 @@ class TestCloudSubscriptionRequest(CloudSubscriptionRequest):
@classmethod
def get_type_id(cls) -> CloudSubscriptionRequestTypeID:
return CloudSubscriptionRequestTypeID.TEST


class CloudSubscriptionValueTypeID(Enum):
"""Type ID for each of our subclasses."""

TEST = 'test'


class CloudSubscriptionValue(IOMultiType[CloudSubscriptionValueTypeID]):
"""Top level class for our multitype."""

@override
@classmethod
def get_type_id(cls) -> CloudSubscriptionValueTypeID:
# Require child classes to supply this themselves. If we
# did a full type registry/lookup here it would require us
# to import everything and would prevent lazy loading.
raise NotImplementedError()

@override
@classmethod
def get_type(
cls, type_id: CloudSubscriptionValueTypeID
) -> type[CloudSubscriptionValue]:
"""Return the subclass for each of our type-ids."""
# pylint: disable=cyclic-import
out: type[CloudSubscriptionValue]

t = CloudSubscriptionValueTypeID
if type_id is t.TEST:
out = TestCloudSubscriptionValue
else:
# Important to make sure we provide all types.
assert_never(type_id)
return out


@ioprepped
@dataclass
class TestCloudSubscriptionValue(CloudSubscriptionValue):
"""Just a test."""

value: Annotated[int | None, IOAttrs('v')]

@override
@classmethod
def get_type_id(cls) -> CloudSubscriptionValueTypeID:
return CloudSubscriptionValueTypeID.TEST
104 changes: 99 additions & 5 deletions tools/bacommon/loggercontrol.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from efro.dataclassio import ioprepped, IOAttrs

if TYPE_CHECKING:
from typing import Self
from typing import Self, Sequence


@ioprepped
Expand All @@ -23,17 +23,64 @@ class LoggerControlConfig:
set to NOTSET.
"""

# Logger names mapped to log-level values (from system logging module).
# Logger names mapped to log-level values (from system logging
# module).
levels: Annotated[dict[str, int], IOAttrs('l', store_default=False)] = (
field(default_factory=dict)
)

def apply(self) -> None:
"""Apply the config to all Python loggers."""
def apply(
self,
*,
warn_unexpected_loggers: bool = False,
warn_missing_loggers: bool = False,
ignore_log_prefixes: list[str] | None = None,
) -> None:
"""Apply the config to all Python loggers.
If 'warn_unexpected_loggers' is True, warnings will be issues for
any loggers not explicitly covered by the config. This is useful
to help ensure controls for all possible loggers are present in
a UI/etc.
If 'warn_missing_loggers' is True, warnings will be issued for
any loggers present in the config that are not found at apply time.
This can be useful for pruning settings for no longer used loggers.
Warnings for any log names beginning with any strings in
'ignore_log_prefixes' will be suppressed. This can allow
ignoring loggers associated with submodules for a given package
and instead presenting only a top level logger (or none at all).
"""
if ignore_log_prefixes is None:
ignore_log_prefixes = []

existinglognames = (
set(['root']) | logging.root.manager.loggerDict.keys()
)

# First issue any warnings they want.
if warn_unexpected_loggers:
for logname in sorted(existinglognames):
if logname not in self.levels and not any(
logname.startswith(pre) for pre in ignore_log_prefixes
):
logging.warning(
'Found a logger not covered by LoggerControlConfig:'
" '%s'.",
logname,
)
if warn_missing_loggers:
for logname in sorted(self.levels.keys()):
if logname not in existinglognames and not any(
logname.startswith(pre) for pre in ignore_log_prefixes
):
logging.warning(
'Logger covered by LoggerControlConfig does not exist:'
' %s.',
logname,
)

# First, update levels for all existing loggers.
for logname in existinglognames:
logger = logging.getLogger(logname)
Expand All @@ -47,6 +94,48 @@ def apply(self) -> None:
if logname not in existinglognames:
logging.getLogger(logname).setLevel(level)

def sanity_check_effective_levels(self) -> None:
"""Checks existing loggers to make sure they line up with us.
This can be called periodically to ensure that a control-config
is properly driving log levels and that nothing else is changing
them behind our back.
"""

existinglognames = (
set(['root']) | logging.root.manager.loggerDict.keys()
)
for logname in existinglognames:
logger = logging.getLogger(logname)
if logger.getEffectiveLevel() != self.get_effective_level(logname):
logging.error(
'loggercontrol effective-level sanity check failed;'
' expected logger %s to have effective level %s'
' but it has %s.',
logname,
logging.getLevelName(self.get_effective_level(logname)),
logging.getLevelName(logger.getEffectiveLevel()),
)

def get_effective_level(self, logname: str) -> int:
"""Given a log name, predict its level if this config is applied."""
splits = logname.split('.')

splen = len(splits)
for i in range(splen):
subname = '.'.join(splits[: splen - i])
thisval = self.levels.get(subname)
if thisval is not None and thisval != logging.NOTSET:
return thisval

# Haven't found anything; just return root value.
thisval = self.levels.get('root')
return (
logging.DEBUG
if thisval is None
else logging.DEBUG if thisval == logging.NOTSET else thisval
)

def would_make_changes(self) -> bool:
"""Return whether calling apply would change anything."""

Expand Down Expand Up @@ -94,7 +183,12 @@ def diff(self, baseconfig: LoggerControlConfig) -> LoggerControlConfig:
def apply_diff(
self, diffconfig: LoggerControlConfig
) -> LoggerControlConfig:
"""Apply a diff config to ourself."""
"""Apply a diff config to ourself.
Note that values that resolve to NOTSET are left intact in the
output config. This is so all loggers expected by either the
base or diff config to exist can be created if desired/etc.
"""
cls = type(self)

# Create a new config (with an indepenent levels dict copy).
Expand Down
6 changes: 5 additions & 1 deletion tools/bacommon/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@


def get_base_logger_control_config_client() -> LoggerControlConfig:
"""Return the logger-control-config used by the ballistica client."""
"""Return the logger-control-config used by the ballistica client.
This should remain consistent since local logger configurations
are stored relative to this.
"""

# By default, go with WARNING on everything to keep things mostly
# clean but show INFO for ba.lifecycle to get basic app
Expand Down

0 comments on commit 33e6893

Please sign in to comment.