6c4bbf3f7ac0bf25846435b91e17743599fe696b
[ric-plt/xapp-frame-py.git] / ricxappframe / xapp_sdl.py
1 # ==================================================================================
2 #       Copyright (c) 2020 Nokia
3 #       Copyright (c) 2020 AT&T Intellectual Property.
4 #
5 #   Licensed under the Apache License, Version 2.0 (the "License");
6 #   you may not use this file except in compliance with the License.
7 #   You may obtain a copy of the License at
8 #
9 #          http://www.apache.org/licenses/LICENSE-2.0
10 #
11 #   Unless required by applicable law or agreed to in writing, software
12 #   distributed under the License is distributed on an "AS IS" BASIS,
13 #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 #   See the License for the specific language governing permissions and
15 #   limitations under the License.
16 # ==================================================================================
17
18 """
19 sdl functionality
20 """
21
22 import msgpack
23 from ricsdl.syncstorage import SyncStorage
24
25
26 class SDLWrapper:
27     """
28     This is a wrapper around the SDL Python interface.
29
30     We do not embed the below directly in the Xapp classes because
31     this SDL wrapper is useful for other python apps, for example A1
32     Mediator uses this verbatim. Therefore, we leave this here as a
33     separate object so it can be used outside of xapps.
34
35     This class optionally uses msgpack for binary (de)serialization:
36     see https://msgpack.org/index.html
37     """
38
39     def __init__(self, use_fake_sdl=False):
40         """
41         init
42
43         Parameters
44         ----------
45         use_fake_sdl: bool (optional, default False)
46             if this is True, then use SDL's in-memory backend,
47             which is very useful for testing since it allows use
48             of SDL without a running SDL or Redis instance.
49             This can be used while developing an xapp and also
50             for monkeypatching during unit testing; e.g., the xapp
51             framework unit tests do this.
52         """
53         if use_fake_sdl:
54             self._sdl = SyncStorage(fake_db_backend="dict")
55         else:
56             self._sdl = SyncStorage()
57
58     def set(self, ns, key, value, usemsgpack=True):
59         """
60         Stores a key-value pair,
61         optionally serializing the value to bytes using msgpack.
62
63         TODO: discuss whether usemsgpack should *default* to True or
64         False here. This seems like a usage statistic question (that we
65         don't have enough data for yet). Are more uses for an xapp to
66         write/read their own data, or will more xapps end up reading data
67         written by some other thing? I think it's too early to know.
68
69         Parameters
70         ----------
71         ns: string
72             SDL namespace
73         key: string
74             SDL key
75         value:
76             Object or byte array to store.  See the `usemsgpack` parameter.
77         usemsgpack: boolean (optional, default is True)
78             Determines whether the value is serialized using msgpack before storing.
79             If usemsgpack is True, the msgpack function `packb` is invoked
80             on the value to yield a byte array that is then sent to SDL.
81             Stated differently, if usemsgpack is True, the value can be anything
82             that is serializable by msgpack.
83             If usemsgpack is False, the value must be bytes.
84         """
85         if usemsgpack:
86             value = msgpack.packb(value, use_bin_type=True)
87         self._sdl.set(ns, {key: value})
88
89     def get(self, ns, key, usemsgpack=True):
90         """
91         Gets the value for the specified namespace and key,
92         optionally deserializing stored bytes using msgpack.
93
94         Parameters
95         ----------
96         ns: string
97             SDL namespace
98         key: string
99             SDL key
100         usemsgpack: boolean (optional, default is True)
101             If usemsgpack is True, the byte array stored by SDL is deserialized
102             using msgpack to yield the original object that was stored.
103             If usemsgpack is False, the byte array stored by SDL is returned
104             without further processing.
105
106         Returns
107         -------
108         Value
109             See the usemsgpack parameter for an explanation of the returned value type.
110             Answers None if the key is not found.
111         """
112         result = None
113         ret_dict = self._sdl.get(ns, {key})
114         if key in ret_dict:
115             result = ret_dict[key]
116             if usemsgpack:
117                 result = msgpack.unpackb(result, raw=False)
118         return result
119
120     def find_and_get(self, ns, prefix, usemsgpack=True):
121         """
122         Gets all key-value pairs in the specified namespace
123         with keys that start with the specified prefix,
124         optionally deserializing stored bytes using msgpack.
125
126         Parameters
127         ----------
128         ns: string
129            SDL namespace
130         prefix: string
131             the key prefix
132         usemsgpack: boolean (optional, default is True)
133             If usemsgpack is True, every byte array stored by SDL is deserialized
134             using msgpack to yield the original value that was stored.
135             If usemsgpack is False, every byte array stored by SDL is returned
136             without further processing.
137
138         Returns
139         -------
140         Dictionary of key-value pairs
141             Each key has the specified prefix.
142             See the usemsgpack parameter for an explanation of the returned value types.
143             Answers an empty dictionary if no keys matched the prefix.
144         """
145
146         # note: SDL "*" usage is inconsistent with real python regex, where it would be ".*"
147         ret_dict = self._sdl.find_and_get(ns, "{0}*".format(prefix))
148         if usemsgpack:
149             ret_dict = {k: msgpack.unpackb(v, raw=False) for k, v in ret_dict.items()}
150         return ret_dict
151
152     def delete(self, ns, key):
153         """
154         Deletes the key-value pair with the specified key in the specified namespace.
155
156         Parameters
157         ----------
158         ns: string
159            SDL namespace
160         key: string
161             SDL key
162         """
163         self._sdl.remove(ns, {key})
164
165     def healthcheck(self):
166         """
167         Checks if the sdl connection is healthy.
168
169         Returns
170         -------
171         bool
172         """
173         return self._sdl.is_active()