ReimuNotMoe / ydotool

Generic command-line automation tool (no X!)
GNU Affero General Public License v3.0
1.46k stars 79 forks source link

RFE: use socket activation on systemd systems #230

Open YHNdnzj opened 7 months ago

YHNdnzj commented 7 months ago

In the context of https://github.com/ReimuNotMoe/ydotool/pull/221, busy retrying should be the last resort. Instead, it's cleaner and probably more efficient to support systemd's socket activation mechanism and only start the daemon when there's a connection.

Paiusco commented 5 months ago

Do you know how easy it is to create a ydotoold.socket? It's still on my list to read about that and see how to create it

Paiusco commented 4 months ago

@YHNdnzj I've been reading a bit on socket creation in the docs

I was wondering if the ListenSpecial=/dev/uinput would be the way to go, but then there's nothing coming from the device block to trigger the start. We basically just have to wait until the /dev/uinput is up to start the daemon, it's not like we're waiting some data come out of it.

I wonder if a dependency After= Requires= on dev-uinput.device would suffice. Although I don't know if the udev rule would cover us for most of the distro/installations, and it'd not add more dependencies (for instance: having to ship and extra udev rule to make sure uinput would always be flagged as systemd, hence having a .device)

Can you provide some guidance here?

YHNdnzj commented 4 months ago

I was wondering if the ListenSpecial=/dev/uinput would be the way to go, but then there's nothing coming from the device block to trigger the start. We basically just have to wait until the /dev/uinput is up to start the daemon, it's not like we're waiting some data come out of it.

Hmm, I don't understand what you're trying to do here? What I'm proposing is to make ydotool <-> ydotoold socket activatable, and that has nothing to do with uinput?

YHNdnzj commented 4 months ago

To implement systemd's socket activation, ydotoold must be taught to receive connection file descriptors from systemd, rather than binding to sockets on its own.

Paiusco commented 4 months ago

No, wait, but that's not the issue mentioned on #221. The issue there is that ydotoold somehow is starting so fast that /dev/uinput is still unavailable, hence the failed to open uinput device: Permission denied message on the log.

I'm trying to make it in a way that the daemon waits/checks if the block device is already available. Can we do that using and extra .socket unit on systemd? Or should we change the daemon code itself to check if a couple of times and only then fail to start?

the CLI (ydotool) is not even part of the equation there, and that is the one that communicates via the socket file.

YHNdnzj commented 4 months ago

The issue there is that ydotoold somehow is starting so fast that /dev/uinput is still unavailable, hence the failed to open uinput device: Permission denied message on the log.

I think the cause of the original issue is that the user service starts before the session is started. And because the access to /dev/uinput is granted through uaccess, i.e. after the session becomes active, the daemon fails to start.

By switching the ydotoold to socket activation we circumvent the problem: the daemon is started only when ydotool is invoked for the first time, which happens after the session activates.

Paiusco commented 4 months ago

oh, so you mean that the first call from the CLI will start the daemon... and then the .socket creates the socket file that the daemon will be attached to.

but wouldn't that mean a big delay the first call from ydotool happens? Meaning that the first time someone would use it, the delay would be considerable... only because we can't check if the uinput is there already or not?

YHNdnzj commented 4 months ago

but wouldn't that mean a big delay the first call from ydotool happens? Meaning that the first time someone would use it, the delay would be considerable...

Well, you'd be surprised how many services on your system are actually socket/dbus-activated ;-)

Try run userdbctl or hostnamectl and see if you could notice the delay? systemd-hostnamed and systemd-userdbd are both activated when needed, and the former even automatically exits if it's idle for a while.

Paiusco commented 4 months ago

I liked it! I'll soon try it out, what do you recommend for the case where one is either starting ydotoold manually or not using systemd? I don't want it to be dependend on it.

That in this case ydotoold falls back to creating the socket itself? (e.g. expects a socket on /path/example, and if not there, creates one)

Never done something like this, want to ~read your mind~ clarify some ideas beforehand :)

YHNdnzj commented 4 months ago

That in this case ydotoold falls back to creating the socket itself?

Yes. If ydotoold didn't acquire the connection fd from a call to sd_listen_fds, it should fall back to creating and listening to the socket in the file system manually.