1 | # pylint: disable=consider-using-with |
||
2 | 1 | """Module to handle the storehouse.""" |
|
3 | 1 | import threading |
|
4 | |||
5 | from kytos.core import log |
||
6 | 1 | from kytos.core.events import KytosEvent |
|
7 | |||
8 | |||
9 | 1 | class StoreHouse: |
|
10 | """Class to handle storehouse.""" |
||
11 | 1 | ||
12 | 1 | @classmethod |
|
13 | 1 | def __new__(cls, *args, **kwargs): |
|
14 | 1 | # pylint: disable=unused-argument |
|
15 | """Make this class a Singleton.""" |
||
16 | 1 | instance = cls.__dict__.get("__instance__") |
|
17 | if instance is not None: |
||
18 | 1 | return instance |
|
19 | 1 | cls.__instance__ = instance = object.__new__(cls) |
|
20 | return instance |
||
21 | |||
22 | def __init__(self, controller): |
||
23 | 1 | """Create a storehouse instance.""" |
|
24 | self.controller = controller |
||
25 | self.namespace = "kytos.mef_eline.circuits" |
||
26 | if "_lock" not in self.__dict__: |
||
27 | self._lock = threading.Lock() |
||
28 | if "box" not in self.__dict__: |
||
29 | self.box = None |
||
30 | self.list_stored_boxes() |
||
31 | |||
32 | 1 | def get_data(self): |
|
33 | """Return the box data.""" |
||
34 | if not self.box: |
||
35 | return {} |
||
36 | self.get_stored_box(self.box.box_id) |
||
37 | return self.box.data |
||
38 | |||
39 | def create_box(self): |
||
40 | 1 | """Create a new box.""" |
|
41 | content = { |
||
42 | 1 | "namespace": self.namespace, |
|
43 | 1 | "callback": self._create_box_callback, |
|
44 | "data": {}, |
||
45 | } |
||
46 | 1 | event = KytosEvent(name="kytos.storehouse.create", content=content) |
|
47 | 1 | self.controller.buffers.app.put(event) |
|
48 | 1 | log.debug("Create box from storehouse.") |
|
49 | |||
50 | 1 | def _create_box_callback(self, _event, data, error): |
|
51 | """Execute the callback to handle create_box.""" |
||
52 | if error: |
||
53 | log.error(f"Can't create box with namespace {self.namespace}") |
||
54 | |||
55 | self.box = data |
||
56 | log.debug(f"Box {self.box.box_id} was created in {self.namespace}.") |
||
57 | 1 | ||
58 | def list_stored_boxes(self): |
||
59 | """List all boxes using the current namespace.""" |
||
60 | name = "kytos.storehouse.list" |
||
61 | content = { |
||
62 | "namespace": self.namespace, |
||
63 | "callback": self._get_or_create_a_box_from_list_of_boxes, |
||
64 | } |
||
65 | |||
66 | event = KytosEvent(name=name, content=content) |
||
67 | self.controller.buffers.app.put(event) |
||
68 | 1 | log.debug(f"Bootstraping storehouse box for {self.namespace}.") |
|
69 | |||
70 | def _get_or_create_a_box_from_list_of_boxes(self, _event, data, _error): |
||
71 | """Create a new box or retrieve the stored box.""" |
||
72 | if data: |
||
73 | self.get_stored_box(data[0]) |
||
74 | else: |
||
75 | self.create_box() |
||
76 | 1 | ||
77 | def get_stored_box(self, box_id): |
||
78 | 1 | """Get box from storehouse.""" |
|
79 | content = { |
||
80 | 1 | "namespace": self.namespace, |
|
81 | "callback": self._get_box_callback, |
||
82 | "box_id": box_id, |
||
83 | "data": {}, |
||
84 | } |
||
85 | 1 | name = "kytos.storehouse.retrieve" |
|
86 | 1 | event = KytosEvent(name=name, content=content) |
|
87 | self._lock.acquire() # Lock to avoid race condition |
||
88 | 1 | log.debug(f'Lock {self._lock} acquired.') |
|
89 | self.controller.buffers.app.put(event) |
||
90 | log.debug(f"Retrieve box with {box_id} from {self.namespace}.") |
||
91 | |||
92 | def _get_box_callback(self, _event, data, error): |
||
93 | """Handle get_box method saving the box or logging with the error.""" |
||
94 | if error: |
||
95 | log.error(f"Box {data.box_id} not found in {self.namespace}.") |
||
96 | |||
97 | self.box = data |
||
98 | self._lock.release() |
||
99 | log.debug(f'Lock {self._lock} released.') |
||
100 | log.debug(f'Box {self.box.box_id} was loaded from storehouse.') |
||
101 | |||
102 | def save_evc(self, evc): |
||
103 | """Save a EVC using the storehouse.""" |
||
104 | self._lock.acquire() # Lock to avoid race condition |
||
105 | log.debug(f"Lock {self._lock} acquired.") |
||
106 | self.box.data[evc.id] = evc.as_dict() |
||
107 | |||
108 | content = { |
||
109 | "namespace": self.namespace, |
||
110 | "box_id": self.box.box_id, |
||
111 | "data": self.box.data, |
||
112 | "callback": self._save_evc_callback, |
||
113 | } |
||
114 | |||
115 | event = KytosEvent(name="kytos.storehouse.update", content=content) |
||
116 | self.controller.buffers.app.put(event) |
||
117 | |||
118 | def _save_evc_callback(self, _event, data, error): |
||
119 | """Display the save EVC result in the log.""" |
||
120 | self._lock.release() |
||
121 | log.debug(f"Lock {self._lock} released.") |
||
122 | if error: |
||
123 | log.error(f"Can't update the {self.box.box_id}") |
||
124 | |||
125 | log.debug(f"Box {data.box_id} was updated.") |
||
126 |