|
25 | 25 | from kazoo.protocol.connection import ConnectionHandler
|
26 | 26 | from kazoo.protocol.paths import _prefix_root, normpath
|
27 | 27 | from kazoo.protocol.serialization import (
|
| 28 | + AddWatch, |
28 | 29 | Auth,
|
29 | 30 | CheckVersion,
|
30 | 31 | CloseInstance,
|
|
38 | 39 | SetACL,
|
39 | 40 | GetData,
|
40 | 41 | Reconfig,
|
| 42 | + RemoveWatches, |
41 | 43 | SetData,
|
42 | 44 | Sync,
|
43 | 45 | Transaction,
|
@@ -248,6 +250,7 @@ def __init__(
|
248 | 250 | self.state_listeners = set()
|
249 | 251 | self._child_watchers = defaultdict(set)
|
250 | 252 | self._data_watchers = defaultdict(set)
|
| 253 | + self._persistent_watchers = defaultdict(set) |
251 | 254 | self._reset()
|
252 | 255 | self.read_only = read_only
|
253 | 256 |
|
@@ -416,8 +419,12 @@ def _reset_watchers(self):
|
416 | 419 | for data_watchers in self._data_watchers.values():
|
417 | 420 | watchers.extend(data_watchers)
|
418 | 421 |
|
| 422 | + for persistent_watchers in self._persistent_watchers.values(): |
| 423 | + watchers.extend(persistent_watchers) |
| 424 | + |
419 | 425 | self._child_watchers = defaultdict(set)
|
420 | 426 | self._data_watchers = defaultdict(set)
|
| 427 | + self._persistent_watchers = defaultdict(set) |
421 | 428 |
|
422 | 429 | ev = WatchedEvent(EventType.NONE, self._state, None)
|
423 | 430 | for watch in watchers:
|
@@ -1644,8 +1651,100 @@ def reconfig_async(self, joining, leaving, new_members, from_config):
|
1644 | 1651 |
|
1645 | 1652 | return async_result
|
1646 | 1653 |
|
| 1654 | + def add_watch(self, path, watch, mode): |
| 1655 | + """Add a watch. |
| 1656 | +
|
| 1657 | + This method adds persistent watches. Unlike the data and |
| 1658 | + child watches which may be set by calls to |
| 1659 | + :meth:`KazooClient.exists`, :meth:`KazooClient.get`, and |
| 1660 | + :meth:`KazooClient.get_children`, persistent watches are not |
| 1661 | + removed after being triggered. |
| 1662 | +
|
| 1663 | + To remove a persistent watch, use |
| 1664 | + :meth:`KazooClient.remove_all_watches` with an argument of |
| 1665 | + :attr:`~kazoo.states.WatcherType.ANY`. |
| 1666 | +
|
| 1667 | + The `mode` argument determines whether or not the watch is |
| 1668 | + recursive. To set a persistent watch, use |
| 1669 | + :class:`~kazoo.states.AddWatchMode.PERSISTENT`. To set a |
| 1670 | + persistent recursive watch, use |
| 1671 | + :class:`~kazoo.states.AddWatchMode.PERSISTENT_RECURSIVE`. |
| 1672 | +
|
| 1673 | + :param path: Path of node to watch. |
| 1674 | + :param watch: Watch callback to set for future changes |
| 1675 | + to this path. |
| 1676 | + :param mode: The mode to use. |
| 1677 | + :type mode: int |
| 1678 | +
|
| 1679 | + :raises: |
| 1680 | + :exc:`~kazoo.exceptions.MarshallingError` if mode is |
| 1681 | + unknown. |
| 1682 | +
|
| 1683 | + :exc:`~kazoo.exceptions.ZookeeperError` if the server |
| 1684 | + returns a non-zero error code. |
| 1685 | + """ |
| 1686 | + return self.add_watch_async(path, watch, mode).get() |
| 1687 | + |
| 1688 | + def add_watch_async(self, path, watch, mode): |
| 1689 | + """Asynchronously add a watch. Takes the same arguments as |
| 1690 | + :meth:`add_watch`. |
| 1691 | + """ |
| 1692 | + if not isinstance(path, str): |
| 1693 | + raise TypeError("Invalid type for 'path' (string expected)") |
| 1694 | + if not callable(watch): |
| 1695 | + raise TypeError("Invalid type for 'watch' (must be a callable)") |
| 1696 | + if not isinstance(mode, int): |
| 1697 | + raise TypeError("Invalid type for 'mode' (int expected)") |
| 1698 | + |
| 1699 | + async_result = self.handler.async_result() |
| 1700 | + self._call( |
| 1701 | + AddWatch(_prefix_root(self.chroot, path), watch, mode), |
| 1702 | + async_result, |
| 1703 | + ) |
| 1704 | + return async_result |
| 1705 | + |
| 1706 | + def remove_all_watches(self, path, watcher_type): |
| 1707 | + """Remove watches from a path. |
| 1708 | +
|
| 1709 | + This removes all watches of a specified type (data, child, |
| 1710 | + any) from a given path. |
| 1711 | +
|
| 1712 | + The `watcher_type` argument specifies which type to use. It |
| 1713 | + may be one of: |
| 1714 | +
|
| 1715 | + * :attr:`~kazoo.states.WatcherType.DATA` |
| 1716 | + * :attr:`~kazoo.states.WatcherType.CHILD` |
| 1717 | + * :attr:`~kazoo.states.WatcherType.ANY` |
| 1718 | +
|
| 1719 | + To remove persistent watches, specify a watcher type of |
| 1720 | + :attr:`~kazoo.states.WatcherType.ANY`. |
| 1721 | +
|
| 1722 | + :param path: Path of watch to remove. |
| 1723 | + :param watcher_type: The type of watch to remove. |
| 1724 | + :type watcher_type: int |
| 1725 | + """ |
| 1726 | + |
| 1727 | + return self.remove_all_watches_async(path, watcher_type).get() |
| 1728 | + |
| 1729 | + def remove_all_watches_async(self, path, watcher_type): |
| 1730 | + """Asynchronously remove watches. Takes the same arguments as |
| 1731 | + :meth:`remove_all_watches`. |
| 1732 | + """ |
| 1733 | + if not isinstance(path, str): |
| 1734 | + raise TypeError("Invalid type for 'path' (string expected)") |
| 1735 | + if not isinstance(watcher_type, int): |
| 1736 | + raise TypeError("Invalid type for 'watcher_type' (int expected)") |
| 1737 | + |
| 1738 | + async_result = self.handler.async_result() |
| 1739 | + self._call( |
| 1740 | + RemoveWatches(_prefix_root(self.chroot, path), watcher_type), |
| 1741 | + async_result, |
| 1742 | + ) |
| 1743 | + return async_result |
| 1744 | + |
1647 | 1745 |
|
1648 | 1746 | class TransactionRequest(object):
|
| 1747 | + |
1649 | 1748 | """A Zookeeper Transaction Request
|
1650 | 1749 |
|
1651 | 1750 | A Transaction provides a builder object that can be used to
|
|
0 commit comments