From 8352d89e43efcb2b9420540a6e2521e3e8d33ee4 Mon Sep 17 00:00:00 2001 From: wygud Date: Wed, 1 Oct 2025 09:26:18 -0400 Subject: [PATCH] Various patches for macOS (orig from @dnks) Generally hackarounds to various modules to cope with either linux-specific runtime incompats, file-name-len limits on macos, or oddly specific to @dnks' setup config template hardcodings XD (Obvi this commit msg was edited/reformated by @goodboy, who's also tossed in interleaved todo bullets around each "change") Hi-level summary, - config/conf.toml for updated UI font size and graphics throttle. - [ ] remove this since it's a project template. - piker/cli/__init__.py -> Changed transport from UDP to TCP in service manager. - [ ] this should be the default anyway, likely it was left that way on a dev-testing branch this history was clone from.. - piker/data/_symcache.py -> Added recursive dict cleaning for TOML serialization. - piker/fsp/_api.py -> Hash-based key for shared memory buffers (macOS compatibility). - piker/tsp/__init__.py -> Hash-based key for history buffers for macOS compatibility. * conflict-reso-note: was adjusted by @goodboy in new code location `.tsp._history` mod and keeps the orig keying for linux, only shortens on mac. - piker/ui/_display.py -> Modified SHM name assertion for macOS compatibility. Unmentioned changes noticed by @goodboy, - adds a new `piker.sh` which should be unnecessary pending proper macos support in `tractor` via `platformdirs`, * https://github.com/goodboy/tractor/pull/342/changes/474f1dc4a72d08605c42ddfa497b9239e3bbb90f --- config/conf.toml | 6 ++++-- piker.sh | 20 ++++++++++++++++++++ piker/data/_symcache.py | 13 ++++++++++++- piker/fsp/_api.py | 8 ++++++-- piker/tsp/_history.py | 14 +++++++++++--- piker/ui/_display.py | 4 +++- pikerd.sh | 20 ++++++++++++++++++++ 7 files changed, 76 insertions(+), 9 deletions(-) create mode 100755 piker.sh create mode 100755 pikerd.sh diff --git a/config/conf.toml b/config/conf.toml index 1f2a64bc..696d0a40 100644 --- a/config/conf.toml +++ b/config/conf.toml @@ -6,9 +6,11 @@ pikerd = [ [ui] -# set custom font + size which will scale entire UI +# set custom font + size which will scale entire UI~ # font_size = 16 +# font_size = 32 # font_name = 'Monospaced' # colorscheme = 'default' # UNUSED -# graphics.update_throttle = 60 # Hz # TODO +# graphics.update_throttle = 120 # Hz #PENDING TODO + diff --git a/piker.sh b/piker.sh new file mode 100755 index 00000000..a16a32c0 --- /dev/null +++ b/piker.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# macOS wrapper for piker to handle missing XDG_RUNTIME_DIR + +# Set up runtime directory for macOS if not already set +if [ -z "$XDG_RUNTIME_DIR" ]; then + # Use macOS standard temp directory with user-specific subdirectory + export XDG_RUNTIME_DIR="/tmp/piker-runtime-$(id -u)" + + # Create the directory if it doesn't exist + if [ ! -d "$XDG_RUNTIME_DIR" ]; then + mkdir -p "$XDG_RUNTIME_DIR" + # Set proper permissions (only user can access) + chmod 700 "$XDG_RUNTIME_DIR" + fi + + echo "Set XDG_RUNTIME_DIR to: $XDG_RUNTIME_DIR" +fi + +# Run piker with all passed arguments +exec uv run piker "$@" \ No newline at end of file diff --git a/piker/data/_symcache.py b/piker/data/_symcache.py index 1f1cb9ec..cfcf6ce6 100644 --- a/piker/data/_symcache.py +++ b/piker/data/_symcache.py @@ -105,6 +105,15 @@ class SymbologyCache(Struct): def write_config(self) -> None: + def clean_dict_for_toml(d): + '''Remove None values from dict recursively for TOML serialization''' + if isinstance(d, dict): + return {k: clean_dict_for_toml(v) for k, v in d.items() if v is not None} + elif isinstance(d, list): + return [clean_dict_for_toml(item) for item in d if item is not None] + else: + return d + # put the backend's pair-struct type ref at the top # of file if possible. cachedict: dict[str, Any] = { @@ -125,7 +134,9 @@ class SymbologyCache(Struct): dct = cachedict[key] = {} for key, struct in table.items(): - dct[key] = struct.to_dict(include_non_members=False) + raw_dict = struct.to_dict(include_non_members=False) + # Clean None values for TOML compatibility + dct[key] = clean_dict_for_toml(raw_dict) try: with self.fp.open(mode='wb') as fp: diff --git a/piker/fsp/_api.py b/piker/fsp/_api.py index 92f8f271..bb2dea50 100644 --- a/piker/fsp/_api.py +++ b/piker/fsp/_api.py @@ -200,9 +200,13 @@ def maybe_mk_fsp_shm( ) # (attempt to) uniquely key the fsp shm buffers + # Use hash for macOS compatibility (31 char limit) + import hashlib actor_name, uuid = tractor.current_actor().uid - uuid_snip: str = uuid[:16] - key: str = f'piker.{actor_name}[{uuid_snip}].{sym}.{target.name}' + # Create short hash of sym and target name + content = f'{sym}.{target.name}' + content_hash = hashlib.md5(content.encode()).hexdigest()[:8] + key: str = f'{uuid[:8]}_{content_hash}.fsp' shm, opened = maybe_open_shm_array( key, diff --git a/piker/tsp/_history.py b/piker/tsp/_history.py index 99261342..a5073933 100644 --- a/piker/tsp/_history.py +++ b/piker/tsp/_history.py @@ -32,6 +32,7 @@ from __future__ import annotations from datetime import datetime from functools import partial from pathlib import Path +import platform from pprint import pformat from types import ModuleType from typing import ( @@ -1380,13 +1381,20 @@ async def manage_history( service: str = name.rstrip(f'.{mod.name}') fqme: str = mkt.get_fqme(delim_char='') + key: str = f'piker.{service}[{uuid[:16]}].{fqme}' + # use a short hash of the `fqme` to deal with macOS + # file-name-len limit.. + if platform.system() == 'Darwin': + import hashlib + fqme_hash: str = hashlib.md5(fqme.encode()).hexdigest()[:8] + key: str = f'{uuid[:8]}_{fqme_hash}' + # (maybe) allocate shm array for this broker/symbol which will # be used for fast near-term history capture and processing. hist_shm, opened = maybe_open_shm_array( size=_default_hist_size, append_start_index=_hist_buffer_start, - - key=f'piker.{service}[{uuid[:16]}].{fqme}.hist', + key=f'{key}.hist', # use any broker defined ohlc dtype: dtype=getattr(mod, '_ohlc_dtype', def_iohlcv_fields), @@ -1405,7 +1413,7 @@ async def manage_history( rt_shm, opened = maybe_open_shm_array( size=_default_rt_size, append_start_index=_rt_buffer_start, - key=f'piker.{service}[{uuid[:16]}].{fqme}.rt', + key=f'{key}.rt', # use any broker defined ohlc dtype: dtype=getattr(mod, '_ohlc_dtype', def_iohlcv_fields), diff --git a/piker/ui/_display.py b/piker/ui/_display.py index 9cedcc63..ee2ba370 100644 --- a/piker/ui/_display.py +++ b/piker/ui/_display.py @@ -214,7 +214,9 @@ async def increment_history_view( hist_chart: ChartPlotWidget = ds.hist_chart hist_viz: Viz = ds.hist_viz # viz: Viz = ds.viz - assert 'hist' in hist_viz.shm.token['shm_name'] + # NOTE: Changed for macOS compatibility with shortened shm names + # assert 'hist' in hist_viz.shm.token['shm_name'] + assert hist_viz.shm.token['shm_name'].endswith('.h') # name: str = hist_viz.name # TODO: seems this is more reliable at keeping the slow diff --git a/pikerd.sh b/pikerd.sh new file mode 100755 index 00000000..447e1370 --- /dev/null +++ b/pikerd.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# macOS wrapper for pikerd to handle missing XDG_RUNTIME_DIR + +# Set up runtime directory for macOS if not already set +if [ -z "$XDG_RUNTIME_DIR" ]; then + # Use macOS standard temp directory with user-specific subdirectory + export XDG_RUNTIME_DIR="/tmp/piker-runtime-$(id -u)" + + # Create the directory if it doesn't exist + if [ ! -d "$XDG_RUNTIME_DIR" ]; then + mkdir -p "$XDG_RUNTIME_DIR" + # Set proper permissions (only user can access) + chmod 700 "$XDG_RUNTIME_DIR" + fi + + echo "Set XDG_RUNTIME_DIR to: $XDG_RUNTIME_DIR" +fi + +# Run pikerd with all passed arguments +exec uv run pikerd "$@" \ No newline at end of file