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