[+] update oom_firefox

1. add l keybinding
    to change in realtime cgroup max memory limit;
  2. make sure keybindings are not working
    when a dialog is opened;
  3. make sure the app correctly handles Ctrl+C;
  4. improve logging format, include a timestamp
    and line locatin;
This commit is contained in:
Siarhei Siniak 2025-12-12 16:41:32 +03:00
parent c0125914d2
commit 0c581d6f5c
12 changed files with 121 additions and 10 deletions

@ -5,7 +5,7 @@ project(
).stdout().strip('\n'), ).stdout().strip('\n'),
# 'online.fxreader.uv', # 'online.fxreader.uv',
# ['c', 'cpp'], # ['c', 'cpp'],
version: '0.1.5.44', version: '0.1.5.54',
# default_options: [ # default_options: [
# 'cpp_std=c++23', # 'cpp_std=c++23',
# # 'prefer_static=true', # # 'prefer_static=true',

@ -13,8 +13,9 @@ import re
import sys import sys
from prompt_toolkit.application import Application from prompt_toolkit.application import Application
from prompt_toolkit.key_binding import KeyBindings from prompt_toolkit.key_binding import KeyBindings, ConditionalKeyBindings
from prompt_toolkit.layout import Layout, HSplit, FloatContainer, Float from prompt_toolkit.layout import Layout, HSplit, FloatContainer, Float
from prompt_toolkit.filters import Condition
from prompt_toolkit.layout.containers import Window from prompt_toolkit.layout.containers import Window
from prompt_toolkit.layout.controls import FormattedTextControl from prompt_toolkit.layout.controls import FormattedTextControl
from prompt_toolkit.widgets import TextArea, Frame, Dialog, Button, Label from prompt_toolkit.widgets import TextArea, Frame, Dialog, Button, Label
@ -23,6 +24,7 @@ from prompt_toolkit.styles import Style
from typing import ( from typing import (
TypedDict, TypedDict,
Any, Any,
Optional,
) )
from collections import OrderedDict from collections import OrderedDict
@ -34,7 +36,7 @@ __created__ = '2025-11-21'
# — Helper for cgroup / slice matching — # — Helper for cgroup / slice matching —
def get_cgroup_path(pid): def get_cgroup_path(pid: int) -> Optional[str]:
try: try:
with open(f'/proc/{pid}/cgroup', 'r') as f: with open(f'/proc/{pid}/cgroup', 'r') as f:
for line in f: for line in f:
@ -264,6 +266,12 @@ def main():
logging.basicConfig( logging.basicConfig(
level=logging.INFO, level=logging.INFO,
format=(
'%(asctime)s '
'%(levelname)-8s '
'%(filename)s:%(lineno)d '
'%(funcName)s %(message)s'
),
handlers=[ handlers=[
logging.handlers.RotatingFileHandler( logging.handlers.RotatingFileHandler(
pathlib.Path('~/.cache/oom_firefox/log').expanduser(), pathlib.Path('~/.cache/oom_firefox/log').expanduser(),
@ -348,8 +356,8 @@ def main():
pass pass
# app.exit() # app.exit()
# signal.signal(signal.SIGINT, lambda s, f: terminate()) signal.signal(signal.SIGINT, lambda s, f: terminate())
# signal.signal(signal.SIGTERM, lambda s, f: terminate()) signal.signal(signal.SIGTERM, lambda s, f: terminate())
def refresh_body(): def refresh_body():
nonlocal firefox_proc nonlocal firefox_proc
@ -397,8 +405,12 @@ def main():
def on_ok(): def on_ok():
txt = ta.text txt = ta.text
for m in re.finditer(r'\((\d+)\)', txt): for m in re.finditer(r'\((\d+)[^\)\d]*\)', txt):
low_priority_pids.add(int(m.group(1))) low_priority_pids.add(int(m.group(1)))
for m in re.finditer(r'^\s*(\d+)\s*$', txt):
low_priority_pids.add(int(m.group(1)))
for m in re.finditer(r'^\s*-(\d+)\s*$', txt):
low_priority_pids.remove(int(m.group(1)))
close_dialog() close_dialog()
refresh_body() refresh_body()
@ -420,6 +432,63 @@ def main():
root_floats.append(f) root_floats.append(f)
app.layout.focus(ta) app.layout.focus(ta)
def change_max_mb(max_mb: int) -> None:
for cmd in (
[
'systemctl',
'--user',
'set-property',
'%s.scope' % args.unit_name,
'MemoryHigh=%dM' % max_mb,
],
[
'systemctl',
'--user',
'set-property',
'%s.scope' % args.unit_name,
'MemoryMax=%dM' % (max_mb * 1.1),
],
):
logger.info(dict(cmd=cmd))
subprocess.check_call(cmd)
args.max_mb = max_mb
def open_limit_dialog():
ta = TextArea(text='', multiline=True, scrollbar=True)
def on_ok():
txt = ta.text
m = re.compile(r'^\s*(\d+)\s*$').match(txt)
a: str = 234234
if m:
change_max_mb(int(m[1]))
close_dialog()
refresh_body()
else:
logger.error('invalid input %s' % txt)
def on_cancel():
close_dialog()
dialog = Dialog(
title='Enter maximum memory threshold in MB',
body=ta,
buttons=[
Button(text='OK', handler=on_ok),
Button(text='Cancel', handler=on_cancel),
],
width=60,
modal=True,
)
f = Float(content=dialog, left=2, top=2)
dialog_float[0] = f
root_floats.append(f)
app.layout.focus(ta)
def open_message(title, message): def open_message(title, message):
def on_close(): def on_close():
close_dialog() close_dialog()
@ -445,6 +514,11 @@ def main():
kb = KeyBindings() kb = KeyBindings()
gkb = ConditionalKeyBindings(
key_bindings=kb,
filter=Condition(lambda: dialog_float[0] is None),
)
@kb.add('q') @kb.add('q')
def _(event): def _(event):
terminate() terminate()
@ -453,9 +527,18 @@ def main():
def _(event): def _(event):
open_pid_dialog() open_pid_dialog()
@kb.add('l')
def _(event):
open_limit_dialog()
HELP_TEXT = 'm=add PIDs, l=change limit, s=settings, a=about, q=quit'
@kb.add('h') @kb.add('h')
def _(event): def _(event):
open_message('Help', 'Keys: m=add PIDs, s=settings, a=about, q=quit') open_message(
'Help',
'Keys: %s' % HELP_TEXT,
)
@kb.add('s') @kb.add('s')
def _(event): def _(event):
@ -479,7 +562,7 @@ def main():
Window( Window(
height=1, height=1,
content=FormattedTextControl( content=FormattedTextControl(
'q=quit, m=PID, h=help, s=setting, a=about' HELP_TEXT,
), ),
), ),
] ]
@ -498,7 +581,7 @@ def main():
app = Application( app = Application(
layout=Layout(root), layout=Layout(root),
key_bindings=kb, key_bindings=gkb,
style=style, style=style,
full_screen=True, full_screen=True,
refresh_interval=args.interval, refresh_interval=args.interval,
@ -531,7 +614,7 @@ def main():
# refresh_body() # refresh_body()
app.run( app.run(
handle_sigint=True # handle_sigint=True
) # from prompttoolkit API :contentReference[oaicite:0]{index=0} ) # from prompttoolkit API :contentReference[oaicite:0]{index=0}
t.join() t.join()

@ -144,6 +144,7 @@ include = [
#'../../../../../follow_the_leader/logic/payments.py', #'../../../../../follow_the_leader/logic/payments.py',
#'../../../../../follow_the_leader/logic/paypal.py', #'../../../../../follow_the_leader/logic/paypal.py',
'online/fxreader/pr34/commands_typed/**/*.py', 'online/fxreader/pr34/commands_typed/**/*.py',
#'online/fxreader/pr34/oom_firefox.py',
] ]
# stubPath = '../mypy-stubs' # stubPath = '../mypy-stubs'
extraPaths = [ extraPaths = [

BIN
releases/whl/online_fxreader_pr34-0.1.5.45-py3-none-any.whl (Stored with Git LFS) Normal file

Binary file not shown.

BIN
releases/whl/online_fxreader_pr34-0.1.5.47-py3-none-any.whl (Stored with Git LFS) Normal file

Binary file not shown.

BIN
releases/whl/online_fxreader_pr34-0.1.5.48-py3-none-any.whl (Stored with Git LFS) Normal file

Binary file not shown.

BIN
releases/whl/online_fxreader_pr34-0.1.5.49-py3-none-any.whl (Stored with Git LFS) Normal file

Binary file not shown.

BIN
releases/whl/online_fxreader_pr34-0.1.5.50-py3-none-any.whl (Stored with Git LFS) Normal file

Binary file not shown.

BIN
releases/whl/online_fxreader_pr34-0.1.5.51-py3-none-any.whl (Stored with Git LFS) Normal file

Binary file not shown.

BIN
releases/whl/online_fxreader_pr34-0.1.5.52-py3-none-any.whl (Stored with Git LFS) Normal file

Binary file not shown.

BIN
releases/whl/online_fxreader_pr34-0.1.5.53-py3-none-any.whl (Stored with Git LFS) Normal file

Binary file not shown.

BIN
releases/whl/online_fxreader_pr34-0.1.5.54-py3-none-any.whl (Stored with Git LFS) Normal file

Binary file not shown.