Skip to content

Validate feed key against IO naming scheme #68

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

Merged
merged 1 commit into from
Mar 26, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions adafruit_io/adafruit_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"""
import time
import json
import re

from adafruit_io.adafruit_io_errors import (
AdafruitIO_RequestError,
Expand All @@ -33,6 +34,18 @@
CLIENT_HEADERS = {"User-Agent": "AIO-CircuitPython/{0}".format(__version__)}


def validate_feed_key(feed_key):
"""Validates a provided feed key against Adafruit IO's system rules.
https://learn.adafruit.com/naming-things-in-adafruit-io/the-two-feed-identifiers
"""
if len(feed_key) > 128: # validate feed key length
raise ValueError("Feed key must be less than 128 characters.")
if not bool(re.match("^[a-z0-9-]+$", feed_key)): # validate key naming scheme
raise TypeError(
"Feed key must contain lower case English letters, numbers, and dash."
)


class IO_MQTT:
"""
Client for interacting with Adafruit IO MQTT API.
Expand Down Expand Up @@ -186,6 +199,7 @@ def add_feed_callback(self, feed_key, callback_method):
:param str callback_method: Name of callback method.

"""
validate_feed_key(feed_key)
self._client.add_topic_callback(
"{0}/f/{1}".format(self._user, feed_key), callback_method
)
Expand All @@ -199,6 +213,7 @@ def remove_feed_callback(self, feed_key):
:param str feed_key: Adafruit IO feed key.

"""
validate_feed_key(feed_key)
self._client.remove_topic_callback("{0}/f/{1}".format(self._user, feed_key))

def loop(self):
Expand Down Expand Up @@ -235,6 +250,7 @@ def subscribe(self, feed_key=None, group_key=None, shared_user=None):

client.subscribe([('temperature'), ('humidity')])
"""
validate_feed_key(feed_key)
if shared_user is not None and feed_key is not None:
self._client.subscribe("{0}/f/{1}".format(shared_user, feed_key))
elif group_key is not None:
Expand Down Expand Up @@ -314,6 +330,7 @@ def unsubscribe(self, feed_key=None, group_key=None, shared_user=None):
client.unsubscribe('temperature', shared_user='adabot')

"""
validate_feed_key(feed_key)
if shared_user is not None and feed_key is not None:
self._client.unsubscribe("{0}/f/{1}".format(shared_user, feed_key))
elif group_key is not None:
Expand Down Expand Up @@ -398,6 +415,7 @@ def publish(self, feed_key, data, metadata=None, shared_user=None, is_group=Fals
io.publish("location-feed", data, metadata)

"""
validate_feed_key(feed_key)
if is_group:
self._client.publish("{0}/g/{1}".format(self._user, feed_key), data)
if shared_user is not None:
Expand All @@ -423,6 +441,7 @@ def get(self, feed_key):

io.get('temperature')
"""
validate_feed_key(feed_key)
self._client.publish("{0}/f/{1}/get".format(self._user, feed_key), "\0")


Expand Down Expand Up @@ -534,6 +553,7 @@ def send_data(self, feed_key, data, metadata=None, precision=None):
:param dict metadata: Optional metadata associated with the data
:param int precision: Optional amount of precision points to send with floating point data
"""
validate_feed_key(feed_key)
path = self._compose_path("feeds/{0}/data".format(feed_key))
if precision:
try:
Expand All @@ -551,6 +571,7 @@ def receive_all_data(self, feed_key):
returned in reverse order.
:param str feed_key: Adafruit IO feed key
"""
validate_feed_key(feed_key)
path = self._compose_path("feeds/{0}/data".format(feed_key))
return self._get(path)

Expand All @@ -559,6 +580,7 @@ def receive_data(self, feed_key):
Return the most recent value for the specified feed.
:param string feed_key: Adafruit IO feed key
"""
validate_feed_key(feed_key)
path = self._compose_path("feeds/{0}/data/last".format(feed_key))
return self._get(path)

Expand All @@ -568,6 +590,7 @@ def delete_data(self, feed_key, data_id):
:param string feed: Adafruit IO feed key
:param string data_id: Data point to delete from the feed
"""
validate_feed_key(feed_key)
path = self._compose_path("feeds/{0}/data/{1}".format(feed_key, data_id))
return self._delete(path)

Expand Down Expand Up @@ -614,6 +637,7 @@ def add_feed_to_group(self, group_key, feed_key):
:param str group_key: Group
:param str feed_key: Feed to add to the group
"""
validate_feed_key(feed_key)
path = self._compose_path("groups/{0}/add".format(group_key))
payload = {"feed_key": feed_key}
return self._post(path, payload)
Expand All @@ -625,6 +649,7 @@ def get_feed(self, feed_key, detailed=False):
:param str feed_key: Adafruit IO Feed Key
:param bool detailed: Returns a more verbose feed record
"""
validate_feed_key(feed_key)
if detailed:
path = self._compose_path("feeds/{0}/details".format(feed_key))
else:
Expand All @@ -638,6 +663,7 @@ def create_new_feed(self, feed_key, feed_desc=None, feed_license=None):
:param str feed_desc: Optional description of feed
:param str feed_license: Optional feed license
"""
validate_feed_key(feed_key)
path = self._compose_path("feeds")
payload = {"name": feed_key, "description": feed_desc, "license": feed_license}
return self._post(path, payload)
Expand All @@ -647,6 +673,7 @@ def delete_feed(self, feed_key):
Deletes an existing feed.
:param str feed_key: Valid feed key
"""
validate_feed_key(feed_key)
path = self._compose_path("feeds/{0}".format(feed_key))
return self._delete(path)

Expand Down