Skip to content

Commit 66414cd

Browse files
committed
Add HTTP Client
1 parent 9378b40 commit 66414cd

6 files changed

Lines changed: 164 additions & 324 deletions

File tree

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
# Copyright (c) 2018-2021 AnimatedLEDStrip
2+
#
3+
# Permission is hereby granted, free of charge, to any person obtaining a copy
4+
# of this software and associated documentation files (the "Software"), to deal
5+
# in the Software without restriction, including without limitation the rights
6+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
# copies of the Software, and to permit persons to whom the Software is
8+
# furnished to do so, subject to the following conditions:
9+
#
10+
# The above copyright notice and this permission notice shall be included in
11+
# all copies or substantial portions of the Software.
12+
#
13+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
# THE SOFTWARE.
20+
import json
21+
from urllib.request import Request, urlopen
22+
from typing import TYPE_CHECKING, List, Dict, Any
23+
24+
from animatedledstrip import RunningAnimationParams, Section, StripInfo
25+
from animatedledstrip.animation_to_run_params import AnimationToRunParams
26+
from animatedledstrip.json_decoder import ALSJsonDecoder
27+
from animatedledstrip.json_encoder import ALSJsonEncoder
28+
29+
if TYPE_CHECKING:
30+
from animatedledstrip.animation_info import AnimationInfo
31+
from animatedledstrip.current_strip_color import CurrentStripColor
32+
33+
34+
class ALSHttpClient:
35+
36+
def __init__(self, ip_address: str):
37+
self.ip_address = ip_address
38+
self.encoder = ALSJsonEncoder()
39+
self.decoder = ALSJsonDecoder()
40+
41+
def _resolve_url(self, url: str) -> str:
42+
return 'http://' + self.ip_address + ':8080' + url
43+
44+
def _get_data(self, url: str) -> Any:
45+
return urlopen(Request(self._resolve_url(url))).read()
46+
47+
def _post_data(self, url: str, data: Any) -> Any:
48+
return urlopen(Request(self._resolve_url(url),
49+
method='POST',
50+
data=bytes(self.encoder.encode(data), 'utf-8'),
51+
headers={'Content-Type': 'application/json'})).read()
52+
53+
def _delete_data(self, url: str) -> Any:
54+
return urlopen(Request(self._resolve_url(url), method='DELETE')).read()
55+
56+
def get_animation_info(self, anim_name: str) -> 'AnimationInfo':
57+
return self.decoder.decode_with_type(self._get_data('/animation/' + anim_name), 'AnimationInfo')
58+
59+
def get_supported_animation_names(self) -> List[str]:
60+
return json.loads(self._get_data('/animations/names'))
61+
62+
def get_supported_animations(self) -> List['AnimationInfo']:
63+
return self.decoder.decode_list_with_type(self._get_data('/animations'), 'AnimationInfo')
64+
65+
def get_supported_animations_map(self) -> Dict[str, 'AnimationInfo']:
66+
return self.decoder.decode_map_with_type(self._get_data('/animations/map'), 'AnimationInfo')
67+
68+
def get_supported_animations_dict(self) -> Dict[str, 'AnimationInfo']:
69+
return self.get_supported_animations_map()
70+
71+
def get_running_animations(self) -> Dict[str, 'RunningAnimationParams']:
72+
return self.decoder.decode_map_with_type(self._get_data('/running'), 'RunningAnimationParams')
73+
74+
def get_running_animations_ids(self) -> List[str]:
75+
return json.loads(self._get_data('/running/ids'))
76+
77+
def get_running_animation_params(self, anim_id: str) -> 'RunningAnimationParams':
78+
return self.decoder.decode_with_type(self._get_data('/running/' + anim_id), 'RunningAnimationParams')
79+
80+
def end_animation(self, anim_id: str) -> 'RunningAnimationParams':
81+
return self.decoder.decode_with_type(self._delete_data('/running/' + anim_id), 'RunningAnimationParams')
82+
83+
def end_animation_from_params(self, anim_params: 'RunningAnimationParams') -> 'RunningAnimationParams':
84+
return self.end_animation(anim_params.anim_id)
85+
86+
def get_sections(self) -> List['Section']:
87+
return self.decoder.decode_list_with_type(self._get_data('/sections'), 'Section')
88+
89+
def get_sections_map(self) -> Dict[str, 'Section']:
90+
return self.decoder.decode_map_with_type(self._get_data('/sections/map'), 'Section')
91+
92+
def get_sections_dict(self) -> Dict[str, 'Section']:
93+
return self.get_sections_map()
94+
95+
def get_section(self, section_id: str) -> 'Section':
96+
return self.decoder.decode_with_type(self._get_data('/sections/' + section_id), 'Section')
97+
98+
def get_full_strip_section(self) -> 'Section':
99+
return self.get_section('fullStrip')
100+
101+
def create_new_section(self, new_section: 'Section') -> 'Section':
102+
return self.decoder.decode_with_type(self._post_data('/sections/newSection', new_section), 'Section')
103+
104+
def start_animation(self, anim_params: 'AnimationToRunParams') -> 'RunningAnimationParams':
105+
return self.decoder.decode_with_type(self._post_data('/start', anim_params), 'RunningAnimationParams')
106+
107+
def get_strip_info(self) -> 'StripInfo':
108+
return self.decoder.decode_with_type(self._get_data('/strip/info'), 'StripInfo')
109+
110+
def get_current_strip_color(self) -> 'CurrentStripColor':
111+
return self.decoder.decode_with_type(self._get_data('/strip/color'), 'CurrentStripColor')
112+
113+
def clear_strip(self):
114+
# TODO: Fix 404
115+
self._post_data('/strip/clear', None)

animatedledstrip/animation_sender.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ def __init__(self, ip_address: str, port_num: int):
6767
self.on_new_section_callback: Optional[Callable[['Section'], Any]] = None
6868
self.on_new_strip_info_callback: Optional[Callable[['StripInfo'], Any]] = None
6969

70-
self._encoder: 'ALSJsonEncoder' = ALSJsonEncoder()
70+
self.encoder: 'ALSJsonEncoder' = ALSJsonEncoder()
71+
7172
self._recv_thread: Optional['Thread'] = None
7273
self._partial_data: bytes = b''
7374

@@ -126,7 +127,7 @@ def end(self) -> 'AnimationSender':
126127
def send(self, data: Union['AnimationToRunParams', 'ClientParams',
127128
'Command', 'EndAnimation', 'Section']) -> 'AnimationSender':
128129
"""Send data to the server"""
129-
self.send_json(self._encoder.encode(data))
130+
self.send_json(self.encoder.encode(data))
130131

131132
return self
132133

animatedledstrip/json_decoder.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1818
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1919
# THE SOFTWARE.
20-
20+
import json
2121
from json import JSONDecoder
2222
from typing import Dict, Any
2323

@@ -52,11 +52,28 @@ def __init__(self, *args, **kwargs):
5252
def decode_dict(self, json: Dict) -> Any:
5353
return self.decode(self.encoder.encode(json))
5454

55+
def decode_with_type(self, obj, data_type: str):
56+
return self.decode_dict(add_dicts(json.loads(obj), {"type": data_type}))
57+
58+
def decode_list_with_type(self, obj, data_type: str):
59+
json_list = json.loads(obj)
60+
decoded_list = []
61+
for o in json_list:
62+
decoded_list.append(self.decode_dict(add_dicts(o, {"type": data_type})))
63+
return decoded_list
64+
65+
def decode_map_with_type(self, obj, data_type: str):
66+
json_dict = json.loads(obj)
67+
decoded_dict = {}
68+
for k in json_dict:
69+
decoded_dict.update({k: self.decode_dict(add_dicts(json_dict[k], {"type": data_type}))})
70+
return decoded_dict
71+
5572
def object_hook(self, obj):
5673
data_type = obj.get('type', '')
5774
if data_type == 'AbsoluteDistance':
5875
return AbsoluteDistance(obj['x'], obj['y'], obj['z'])
59-
if data_type == 'AnimationInfo':
76+
elif data_type == 'AnimationInfo':
6077
return AnimationInfo(
6178
name=obj['name'],
6279
abbr=obj['abbr'],

animatedledstrip/json_encoder.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class ALSJsonEncoder(JSONEncoder):
2727

2828
def default(self, o: Any) -> Any:
2929
# print(type(o))
30-
if hasattr(o, "json_dict"):
30+
if hasattr(o, 'json_dict'):
3131
# noinspection PyCallingNonCallable
3232
return o.json_dict()
3333
else:

0 commit comments

Comments
 (0)