-
Notifications
You must be signed in to change notification settings - Fork 453
Add ntfy as a notification backend #1076
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
base: master
Are you sure you want to change the base?
Conversation
The SMTP notification backend looks quite complicated and is tricky to setup so I wrote a ntfy backend based on what's in the Stdout subscriber object. Everything has been tested to work on with my ntfy setup, except for the new_thread callback, which i'm not sure exactly how to trigger. It is also currently missing documentations. I will add the relevant sections to the documentation if the patch is considered useful.
isso/ext/notifications.py
Outdated
| self.notify("comment %(id)s activated" % thread) | ||
|
|
||
| def notify(self, str): | ||
| response = requests.post(urljoin(self.conf.get("url"),self.conf.get("topic")), data = str.encode(encoding='utf-8')) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need requests for this, isn't just urllib sufficient?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll go through the urllib tutorial and remove the requests dependency. The ntfy backend only needs to make post requests so it shouldn't be difficult to make the switch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed the dependency on requests and the backend now calls urlopen directly for connections to the nfty server. I wonder if the proper way to do this is to extend utils/http.py to also take an optional data argument, although urlopen from urllib seems more than enough for this type of one-off notification messages.
| break | ||
|
|
||
|
|
||
| class Ntfy(object): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're going to have multiple notifiers, we should probably have a common base class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes sense. I also want to add there's a lot of overlap between the Stdout and the Ntfy objects. The latter uses the exact same plaintext message that the former emits and the only difference is that the message in Ntfy goes to an http request instead of stdout. Could add another common class for Stdout and Nfty to avoid writing the same logic twice.
|
Curious about @ix5 's thoughts as well. My main concern here is feature creep - if ntfy.sh is sufficiently popular then I think it makes sense to support. But we don't really want to support a dozen different notification mechanisms because it's hard to keep them from regressing and would give users a bad experience. |
There is already the utility library http.curl around but sadly it doesn't seem to support passing data for POST requests
|
@jelmer thank you for notifying. We already have a PR open for a very similar thing: Feature: add webhook notification capability #724 (which sadly has languished for a while). While I like the simplicity of this PR, I think ultimately #724 is the way to go. @jelmer should we have another go at encouraging the submitter to update the PR and get it ready for merging? @yiyunliu maybe you would also be up to the task since @ Guts seems to have stepped back a bit. (Also #457 was aimed at a different functionality, just to keep on the radar about notification backends) |
ix5
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In case we decide to go along with this PR, this would be my suggested changes. @yiyunliu no need to act upon this yet before a decision has been made, just letting you know.
| if smtp_backend or conf.getboolean("general", "reply-notifications"): | ||
| subscribers.append(SMTP(self)) | ||
|
|
||
| if ntfy_backend: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to introduce a ntfy_backend variable, you can just move this block below elif backend == "ntfy"
|
|
||
| from email.utils import parseaddr, formataddr | ||
| from configparser import ConfigParser, NoOptionError, NoSectionError, DuplicateSectionError | ||
| from urllib.parse import urlparse |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unused import, leftover?
|
|
||
| def notify(self, str): | ||
| topic_url = urljoin(self.conf.get("url"),self.conf.get("topic")) | ||
| try: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some simple retry/backoff logic here, perhaps a bit more sophisticated than time.sleep(60) as we do with SMTP?
| try: | ||
| with urlopen(topic_url,str.encode(encoding='utf-8')) as response: | ||
| pass | ||
| except URLError as e: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not that I think it matters much, but other types of errors (apart from URLError) are not caught and reported here.
| def notify(self, str): | ||
| topic_url = urljoin(self.conf.get("url"),self.conf.get("topic")) | ||
| try: | ||
| with urlopen(topic_url,str.encode(encoding='utf-8')) as response: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please leave a space between topic_url and str.encode)
| with urlopen(topic_url,str.encode(encoding='utf-8')) as response: | |
| with urlopen(topic_url, str.encode(encoding='utf-8')) as response: |
| self.notify("comment %(id)s activated" % thread) | ||
|
|
||
| def notify(self, str): | ||
| topic_url = urljoin(self.conf.get("url"),self.conf.get("topic")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| topic_url = urljoin(self.conf.get("url"),self.conf.get("topic")) | |
| topic_url = urljoin(self.conf.get("url"), self.conf.get("topic")) |
| self.notify("\n".join(response_strs)) | ||
|
|
||
| def _edit_comment(self, comment): | ||
| self.notify(f"comment {comment["id"]} edited: {json.dumps(comment)}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we send raw JSON to ntfy channels? I suppose the audience for ntfy is rather technically inclined but could we format this a bit more nicely?
| pass | ||
| except URLError as e: | ||
| if hasattr(e, 'reason'): | ||
| logger.exception(f"Failed to reach the ntfy server.\nError code: {e.code}" ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No newlines for log output here (and below) would be my preference.
I'd be happy to take a look at the draft and try rebasing the PR to and resolving some of the remaining issues. I'm not really familiar with the spec of webhook, however, so I might have trouble coming up with good test cases other than checking if it works with ntfy's webhook support. |
Checklist
CHANGES.rstbecause this is a user-facing change or an important bugfixWhat changes does this Pull Request introduce?
I wrote a ntfy.sh backend based on what's in the Stdout subscriber object. Everything has been tested to work on with my ntfy setup, except for the new_thread callback, which i'm not sure exactly how to trigger.
ntfy.shis quite easy to set up and satisfies my need to run the notification service locally on my VPN. SMTP, on the other hand, is kind of tricky to setup compared to the straightforward API thatntfyprovides.If the patch is considered useful, I'd be happy to start working on the checklist items. (Might need some help on the testing side)
Why is this necessary?
N/A because it's a feature?