1# coding=utf-8
2
3from __future__ import absolute_import
4import datetime
5import threading
6
7lock = threading.Lock()
8
9
10class TempIntent(object):
11    timeout = 1000  # milliseconds
12    store = None
13
14    def __init__(self, timeout=1000, store=None):
15        self.timeout = timeout
16        if store is None:
17            raise NotImplementedError
18
19        self.store = store
20
21    def get(self, kind, *keys):
22        with lock:
23            # iter all requested keys
24            for key in keys:
25                hit = False
26
27                # skip key if invalid
28                if not key:
29                    continue
30
31                # valid kind?
32                if kind in self.store:
33                    now = datetime.datetime.now()
34                    key = str(key)
35
36                    # iter all known kinds (previously created)
37                    for known_key in self.store[kind].keys():
38                        # may need locking, for now just play it safe
39                        data = self.store[kind].get(known_key, {})
40                        ends = data.get("timeout")
41                        if not ends:
42                            continue
43
44                        timed_out = False
45                        if now > ends:
46                            timed_out = True
47
48                        # key and kind in storage, and not timed out = hit
49                        if known_key == key and not timed_out:
50                            hit = True
51
52                        if timed_out:
53                            try:
54                                del self.store[kind][key]
55                            except:
56                                continue
57
58                    if hit:
59                        return True
60        return False
61
62    def resolve(self, kind, key):
63        with lock:
64            if kind in self.store and key in self.store[kind]:
65                del self.store[kind][key]
66                return True
67            return False
68
69    def set(self, kind, key, data=None, timeout=None):
70        with lock:
71            if kind not in self.store:
72                self.store[kind] = {}
73
74            key = str(key)
75            self.store[kind][key] = {
76                "data": data,
77                "timeout": datetime.datetime.now() + datetime.timedelta(milliseconds=timeout or self.timeout)
78            }
79
80    def has(self, kind, key):
81        with lock:
82            if kind not in self.store:
83                return False
84            return key in self.store[kind]
85
86    def cleanup(self):
87        now = datetime.datetime.now()
88        clear_all = False
89        for kind, info in self.store.items():
90            for key, intent_data in info.items():
91                # legacy intent data, clear everything
92                if not isinstance(intent_data, dict):
93                    clear_all = True
94                    continue
95
96                if now > intent_data["timeout"]:
97                    del self.store[kind][key]
98        if clear_all:
99            self.store.clear()
100
101        self.store.save()
102
103