Skip to content
This repository was archived by the owner on Jun 7, 2021. It is now read-only.

Commit 205fda7

Browse files
committed
Removed links and added action cancellation
1 parent ad1f757 commit 205fda7

4 files changed

Lines changed: 51 additions & 47 deletions

File tree

webthing/action.py

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""High-level Action base class implementation."""
22

3+
from copy import deepcopy
34
import uuid
45
import asyncio
56
from .utils import timestamp
@@ -17,6 +18,8 @@ def __init__(self, thing, name, target, input_):
1718
name -- name of the action
1819
input_ -- any action inputs
1920
"""
21+
self._task = None
22+
2023
self.id = uuid.uuid4().hex
2124
self.thing = thing
2225
self.name = name
@@ -102,23 +105,29 @@ async def start(self):
102105
self.thing.action_notify(self)
103106
# If the action function is async
104107
if asyncio.iscoroutinefunction(self.target_function):
105-
# Await the action function
106-
self.output = await self.target_function(self.input)
108+
self._task = asyncio.ensure_future(self.target_function(self.input))
107109
# If the action function is not async
108110
else:
109111
# Run in the default ThreadPoolExecutor
110-
self.output = await asyncio.get_event_loop().run_in_executor(
112+
self._task = asyncio.get_event_loop().run_in_executor(
111113
None, self.target_function, self.input
112114
)
113-
self.finish()
115+
self._task.add_done_callback(self.finish)
114116

115117
def cancel(self):
116-
# TODO: Implement coroutine cancellation
117-
pass
118+
if self._task:
119+
self._task.cancel()
118120

119-
def finish(self):
121+
def finish(self, future):
120122
"""Finish performing the action."""
121-
self.status = "completed"
123+
try:
124+
self.output = future.result()
125+
self.status = "completed"
126+
except asyncio.CancelledError:
127+
self.status = "cancelled"
128+
except Exception as e:
129+
self.output = str(e)
130+
self.status = "error"
122131
self.time_completed = timestamp()
123132
self.thing.action_notify(self)
124133

@@ -137,6 +146,28 @@ def __init__(self, thing, name, invokeaction=None, metadata=None):
137146

138147
self.queue = []
139148

149+
def as_action_description(self):
150+
"""
151+
Get the action description.
152+
153+
Returns a dictionary describing the action.
154+
"""
155+
description = deepcopy(self.metadata)
156+
157+
# Create forms
158+
if "forms" not in description:
159+
description["forms"] = []
160+
161+
description["forms"].append(
162+
{
163+
"op": "invokeaction",
164+
"href": self.href_prefix + self.href,
165+
"htv:methodName": "POST",
166+
}
167+
)
168+
169+
return description
170+
140171
def invokeaction(self, input_):
141172
action_obj = ActionObject(
142173
self.thing, self.name, self.invokeaction_forwarder, input_

webthing/property.py

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -65,17 +65,6 @@ def as_property_description(self):
6565
if "readOnly" not in description and self.value.readonly:
6666
description["readOnly"] = True
6767

68-
# Create links
69-
if "links" not in description:
70-
description["links"] = []
71-
72-
description["links"].append(
73-
{
74-
"rel": "property",
75-
"href": self.href_prefix + self.href,
76-
}
77-
)
78-
7968
# Create forms
8069
if "forms" not in description:
8170
description["forms"] = []

webthing/server.py

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@ async def get(self):
436436
self.set_status(404)
437437
return
438438

439-
await self.represent_response(self.thing.get_action_descriptions())
439+
await self.represent_response(self.thing.get_action_object_descriptions())
440440

441441
async def post(self):
442442
"""
@@ -490,7 +490,7 @@ async def get(self, action_name=None):
490490
return
491491

492492
await self.represent_response(
493-
self.thing.get_action_descriptions(action_name=action_name)
493+
self.thing.get_action_object_descriptions(action_name=action_name)
494494
)
495495

496496
async def post(self, action_name=None):
@@ -541,21 +541,6 @@ async def get(self, action_name=None, action_id=None):
541541

542542
await self.represent_response(action.as_action_description())
543543

544-
def put(self, action_name=None, action_id=None):
545-
"""
546-
Handle a PUT request.
547-
548-
TODO: this is not yet defined in the spec
549-
550-
action_name -- name of the action from the URL path
551-
action_id -- the action ID from the URL path
552-
"""
553-
if self.thing is None:
554-
self.set_status(404)
555-
return
556-
557-
self.set_status(200)
558-
559544
def delete(self, action_name=None, action_id=None):
560545
"""
561546
Handle a DELETE request.

webthing/thing.py

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def as_thing_description(self):
4848
"title": self.title,
4949
"@context": self.context,
5050
"properties": self.get_property_descriptions(),
51-
"actions": {},
51+
"actions": self.get_action_descriptions(),
5252
"events": {},
5353
"links": [
5454
{
@@ -66,15 +66,6 @@ def as_thing_description(self):
6666
],
6767
}
6868

69-
for name, action in self.actions.items():
70-
thing["actions"][name] = action.metadata
71-
thing["actions"][name]["links"] = [
72-
{
73-
"rel": "action",
74-
"href": "{}/actions/{}".format(self.href_prefix, name),
75-
},
76-
]
77-
7869
for name, event in self.available_events.items():
7970
thing["events"][name] = event["metadata"]
8071
thing["events"][name]["links"] = [
@@ -183,7 +174,15 @@ def get_property_descriptions(self):
183174
"""
184175
return {k: v.as_property_description() for k, v in self.properties.items()}
185176

186-
def get_action_descriptions(self, action_name=None):
177+
def get_action_descriptions(self):
178+
"""
179+
Get the thing's available actions as a dictionary.
180+
181+
Returns the actions as a dictionary, i.e. name -> description.
182+
"""
183+
return {k: v.as_action_description() for k, v in self.actions.items()}
184+
185+
def get_action_object_descriptions(self, action_name=None):
187186
"""
188187
Get the thing's action objects as an array.
189188

0 commit comments

Comments
 (0)