Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible to send notifications to other users and/or send from daemon process? #23

Closed
michelcrypt4d4mus opened this issue May 16, 2024 · 6 comments

Comments

@michelcrypt4d4mus
Copy link
Contributor

I tried to call create_notification() from a daemon process that runs as root and it failed with builtins.ValueError: bad value(s) in fds_to_keep. That sort of makes sense given that root isn't a regular user. While I'm not sure this is even possible I was hoping to find a parameter for the userInfo argument that the objective-c NSUserNotification constructor takes and didn't see anything. Would it be possible to implement such a thing? I could maybe help with a pull request.

@michelcrypt4d4mus michelcrypt4d4mus changed the title Possible to send notifications to other users? Possible to send notifications to other users and/or send from daemon process? May 17, 2024
@michelcrypt4d4mus
Copy link
Contributor Author

I just tried using the package from a daemon running in user space (~/Library/LaunchAgents, not /Library/LaunchDaemons) and ran into the same issue.

I was somewhat surprised to see that a shell call to osascript was able to work when running a daemon in user space (running osascript as a root:wheel daemon does not work). e.g. this works:

import os

command = f'''
    osascript -e 'display notification "This is a notification" with title "Notifying"'
'''

os.system(command)

but this does not:

from mac_notifications import client

client.create_notification(title="This is a notification", subtitle="Notifying")

The error is the same as when I attempted to call create_notification() from the root daemon (builtins.ValueError: bad value(s) in fds_to_keep), here's the full stack trace:

File "/Users/uzor/workspace/fork_canary/env/lib/python3.12/site-packages/opencanary/modules/__init__.py", line 207, in send_notification
	    client.create_notification(
	  File "/Users/uzor/workspace/fork_canary/env/lib/python3.12/site-packages/mac_notifications/client.py", line 66, in create_notification
	    return get_notification_manager().create_notification(notification_config)
	  File "/Users/uzor/workspace/fork_canary/env/lib/python3.12/site-packages/mac_notifications/client.py", line 21, in get_notification_manager
	    return NotificationManager()
	  File "/Users/uzor/workspace/fork_canary/env/lib/python3.12/site-packages/mac_notifications/singleton.py", line 17, in __call__
	    instance = super().__call__(*args, **kwargs)
	  File "/Users/uzor/workspace/fork_canary/env/lib/python3.12/site-packages/mac_notifications/manager.py", line 51, in __init__
	    self._callback_queue: SimpleQueue = SimpleQueue()
	  File "/opt/homebrew/Cellar/python@3.12/3.12.3/Frameworks/Python.framework/Versions/3.12/lib/python3.12/multiprocessing/context.py", line 113, in SimpleQueue
	    return SimpleQueue(ctx=self.get_context())
	  File "/opt/homebrew/Cellar/python@3.12/3.12.3/Frameworks/Python.framework/Versions/3.12/lib/python3.12/multiprocessing/queues.py", line 363, in __init__
	    self._rlock = ctx.Lock()
	  File "/opt/homebrew/Cellar/python@3.12/3.12.3/Frameworks/Python.framework/Versions/3.12/lib/python3.12/multiprocessing/context.py", line 68, in Lock
	    return Lock(ctx=self.get_context())
	  File "/opt/homebrew/Cellar/python@3.12/3.12.3/Frameworks/Python.framework/Versions/3.12/lib/python3.12/multiprocessing/synchronize.py", line 169, in __init__
	    SemLock.__init__(self, SEMAPHORE, 1, 1, ctx=ctx)
	  File "/opt/homebrew/Cellar/python@3.12/3.12.3/Frameworks/Python.framework/Versions/3.12/lib/python3.12/multiprocessing/synchronize.py", line 80, in __init__
	    register(self._semlock.name, "semaphore")
	  File "/opt/homebrew/Cellar/python@3.12/3.12.3/Frameworks/Python.framework/Versions/3.12/lib/python3.12/multiprocessing/resource_tracker.py", line 174, in register
	    self._send('REGISTER', name, rtype)
	  File "/opt/homebrew/Cellar/python@3.12/3.12.3/Frameworks/Python.framework/Versions/3.12/lib/python3.12/multiprocessing/resource_tracker.py", line 182, in _send
	    self.ensure_running()
	  File "/opt/homebrew/Cellar/python@3.12/3.12.3/Frameworks/Python.framework/Versions/3.12/lib/python3.12/multiprocessing/resource_tracker.py", line 148, in ensure_running
	    pid = util.spawnv_passfds(exe, args, fds_to_pass)
	  File "/opt/homebrew/Cellar/python@3.12/3.12.3/Frameworks/Python.framework/Versions/3.12/lib/python3.12/multiprocessing/util.py", line 456, in spawnv_passfds
	    return _posixsubprocess.fork_exec(
	builtins.ValueError: bad value(s) in fds_to_keep

@michelcrypt4d4mus
Copy link
Contributor Author

This seems to happen not just when run by launchctl because i ran into the same error running via a twistd server process. Seems to fail on instantiating SimpleQueue, this line:

self._callback_queue: SimpleQueue = SimpleQueue()

I found that if I just disabled all of the multiprocessing stuff I was able to make your package work without issue in the context I need.

@Jorricks
Copy link
Owner

This seems to happen not just when run by launchctl because i ran into the same error running via a twistd server process. Seems to fail on instantiating SimpleQueue, this line:

self._callback_queue: SimpleQueue = SimpleQueue()

I found that if I just disabled all of the multiprocessing stuff I was able to make your package work without issue in the context I need.

Hi @michelcrypt4d4mus,

First of all, thanks for raising the issue and using the package. Nice to see you found a solution.

Do you think we could make this an option in the package where you specify whether you want an asynchronous flow or the flow without any multiprocessing?

@michelcrypt4d4mus
Copy link
Contributor Author

Yes, that's more or less exactly what I did, albeit in a very janky af fashion. It's your package; can be configured however you want. Could just be an argument to create_notification() maybe?

@michelcrypt4d4mus
Copy link
Contributor Author

So this is pretty weird - i found that if i instantiate a SimpleQueue() object in my application before any calls are made to macos_notifications then the problem goes away.

my application is based on twistd / Twisted which i know does some of its own thread management so i'm guessing it's somehow related to that. either way it's almost certainly a bug somewhere - not in this package, most likely in Twisted. I found this 5 year old issue where someone running a twisted based web app ran into the same error but there wasn't much in the way of resolution.

interestingly a new problem crops up when i do that in the form of a warning:

python3.12/multiprocessing/resource_tracker.py:254: UserWarning: resource_tracker: There appear to be 2 leaked semaphore objects to clean up at shutdown

which strikes me as almost certainly a more benign version of the error that caused the crash, given that the "fd" fds_to_keep in the original error message is referring to file descriptor semaphores for IPC. actual error is generated here in the cython code.

@michelcrypt4d4mus
Copy link
Contributor Author

closing this because it's actually an issue with twisted itself

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants