Skip to content

Commit

Permalink
Merge pull request RIOT-OS#3 from Citrullin/wot_gcoap_jkrhb
Browse files Browse the repository at this point in the history
New version of generate.py and affordances JSON scheme
  • Loading branch information
Citrullin authored Dec 26, 2020
2 parents cfe46f2 + 362f53d commit 8a3f5e1
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 104 deletions.
22 changes: 11 additions & 11 deletions tests/wot_coap_generation/config/wot_td/.coap_affordances.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@
},
"events": {
},
"actions": [
{
"name": "toggle",
"url": "/led/toggle",
"handler": {
"file": "toggle.c",
"name": "_led_toggle_handler",
"multipleUsage": false
},
"method": "POST",
"actions": {
"toggle": {
"forms": [
{
"handler_file": "toggle.c",
"handler_function": "_led_toggle_handler",
"href": "/led/toggle",
"cov:methodName": "POST"
}
],
"titles": {
"de": "Deutscher Titel",
"en": "English title"
Expand Down Expand Up @@ -44,5 +44,5 @@
}
}
}
]
}
}
206 changes: 113 additions & 93 deletions tests/wot_coap_generation/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,143 +3,163 @@
import argparse
import sys

currentDirectory = os.getcwd()
result_file = currentDirectory + "/result.c"
AFFORDANCE_TYPES = ['properties', 'actions', 'events']

current_directory = os.getcwd()
result_file = current_directory + "/result.c"
result = ""
coapJsons = []
thingJsons = []
multipleUsage = {
coap_jsons = []
thing_jsons = []
multiple_usage = {
"properties": [],
"actions": [],
"events": []
}
coapAffordances = {
coap_affordances = {
"properties": [],
"actions": [],
"events": []
}

parser = argparse.ArgumentParser(description='Web of Things helper script')
parser.add_argument('--board', help='Define used board')
parser.add_argument('--saul', action='store_true', help='Define if WoT TD SAUL is used')
parser.add_argument('--saul', action='store_true',
help='Define if WoT TD SAUL is used')
parser.add_argument('--security', help='Define what security is used')


def dict_raise_on_duplicates(ordered_pairs):
"""Reject duplicate keys."""
d = {}
for k, v in ordered_pairs:
if k in d:
raise ValueError("duplicate key: %r" % (k,))
else:
d[k] = v
return d


def add_content(content):
global result
result += content


def write_to_c_file(content):
global result
f = open(result_file, "w")
f.write(result)
f.close()

def validate_coap_json(coapJson):
assert coapJson['name'], "ERROR: name in coap_affordances.json missing"
assert coapJson['url'], "ERROR: url in coap_affordances.json missing"
assert coapJson['handler'], "ERROR: handler in coap_affordances.json missing"
assert coapJson['method'], "ERROR: method in coap_affordances.json missing"

def validate_thing_json(thingJson):
assert thingJson['titles'], "ERROR: name in thing.json missing"
assert thingJson['defaultLang'], "ERROR: name in thing.json missing"

def validate_unique_name(name, jsons, propName):
count = 0
for j in jsons:
for aff in j[propName]:
if aff[name] == name:
count += 1
assert not(count > 1), "ERROR: Each coap affordance has to be unique"

def validate_coap_affordances(coapJsons):
for coapJson in coapJsons:
properties = coapJson['properties']
for prop in properties:
name = prop['name']
validate_unique_name(name, coapJsons, 'properties')

events = coapJson['events']
for event in events:
name = event['name']
validate_unique_name(name, coapJsons, 'events')

actions = coapJson['actions']
for action in actions:
name = action['name']
validate_unique_name(name, coapJsons, 'actions')

def find_all_coap_methods(handlerName, affName, coapJsons):
methods = []
for coapJson in coapJsons:
for aff in coapJson[affName]:
if aff['handler']['name'] == handlerName:
methods.append(aff['method'])
return methods

def validate_coap_json(coap_jsons):
# TODO: Add actual validator for (different types of) affordances
assert coap_jsons['name'], "ERROR: name in coap_affordances.json missing"
assert coap_jsons['url'], "ERROR: url in coap_affordances.json missing"
assert coap_jsons['handler'], "ERROR: handler in coap_affordances.json missing"
assert coap_jsons['method'], "ERROR: method in coap_affordances.json missing"


def validate_thing_json(thing_json):
# TODO: Expand thing validation
assert thing_json['titles'], "ERROR: name in thing.json missing"
assert thing_json['defaultLang'], "ERROR: name in thing.json missing"


def write_coap_resources(coap_resources):
add_content("const coap_resource_t _coap_resources[] = {\n")
resources = sorted(coap_resources, key=lambda k: k['url'])
for resource in resources:
add_content("{ \"" + resource['url'] + "\", COAP_GET | COAP_MATCH_SUBTREE, _echo_handler, NULL }")
i = len(resource['methods'])
for method in resource['methods']:
add_content(method)
if i > 0:
sorted_resources = sorted(coap_resources, key=lambda k: k['href'])
for resource in sorted_resources:
add_content(f' {{"{resource["href"]}", ')
for index, method in enumerate(resource['methods']):
if index > 0:
add_content(" | ")
add_content(", " + resource['handler']['name'] + ", NULL }")


add_content("\n};")

def generate_coap_resouces():
coapRessources = []
for coapJson in coapJsons:
properties = coapJson['properties']
for prop in properties:
handler = prop['handler']
if 0 == len(filter(lambda x: handler == x, coapRessources)):
url = prop['url']
methods = find_all_coap_methods(handler, 'properties', coapJsons)
coapRessources.append({
'url': url,
'handler': handler,
'methods': methods
})
print(coapRessources)
write_coap_resources(coapRessources)

add_content(method)
add_content(", " + resource['handler'] + ", NULL},\n")

add_content("};")


def generate_coap_resources():
coap_resources = []
for coap_json in coap_jsons:
for affordance_type in AFFORDANCE_TYPES:
for affordance_name, affordance in coap_json[affordance_type].items():
assert_unique_affordance(affordance_name)
multiple_usage[affordance_type].append(affordance_name)
forms = affordance["forms"]
resources = extract_coap_resources(forms)
coap_resources.extend(resources)
write_coap_resources(coap_resources)


def assert_unique_affordance(affordance_name: str):
for defined_affordances in multiple_usage.values():
assert affordance_name not in defined_affordances, "ERROR: Each coap affordance has to be unique"


def extract_coap_resources(resources: list) -> list:
hrefs = []
handlers = []
methods = []
for resource in resources:
href = resource['href']
handler_function = resource['handler_function']
method_name = resource['cov:methodName']
if href not in hrefs:
hrefs.append(href)
handlers.append(handler_function)
methods.append([f"COAP_{method_name}"])
else:
index = hrefs.index(href)
assert handlers[
index] == handler_function, f"ERROR: Different handler function for {href}"
assert method_name not in methods[
index], f"ERROR: Method {method_name} already used for href {href}"
methods[index].append(f"COAP_{method_name}")

resource_list = []

for index, href in enumerate(hrefs):
dictionary = {}
dictionary["href"] = href
dictionary["handler"] = handlers[index]
dictionary["methods"] = methods[index]
resource_list.append(dictionary)

return resource_list


if __name__ == '__main__':
args = parser.parse_args()
assert args.board, "ERROR: Argument board has to be defined"
assert args.security, "ERROR: Argument security has to be defined"

thingDefiniton = currentDirectory + "/config/wot_td/.thing.json"
thing_definiton = f"{current_directory}/config/wot_td/.thing.json"
try:
f = open(thingDefiniton)
thingJson = json.loads(f.read())
f = open(thing_definiton)
thing_json = json.loads(f.read())
validate_thing_json(thing_json)
except IOError:
print("ERROR: Thing definition in " + thingDefiniton + " is missing")
print(f"ERROR: Thing definition in {thing_definiton} is missing")
sys.exit(0)
except json.decoder.JSONDecodeError:
print("ERROR: json in " + thingDefiniton + " is not valid")
print(f"ERROR: json in {thing_definiton} is not valid")
sys.exit(0)
finally:
f.close()
coapAffordances = currentDirectory + "/config/wot_td/.coap_affordances.json"

coap_affordances = f"{current_directory}/config/wot_td/.coap_affordances.json"
try:
f = open(coapAffordances)
coapJson = json.loads(f.read())
validate_coap_affordances(coapJsons)
coapJsons.append(coapJson)
f = open(coap_affordances)
coap_json = json.loads(
f.read(), object_pairs_hook=dict_raise_on_duplicates)
coap_jsons.append(coap_json)
except IOError:
print("INFO: Coap definition in " + coapAffordances + " not present")
print(f"INFO: Coap definition in {coap_affordances} not present")
except json.decoder.JSONDecodeError:
print("ERROR: json in " + coapAffordances + " is not valid")
print(f"ERROR: json in {coap_affordances} is not valid")
sys.exit(0)
finally:
f.close()
generate_coap_resouces()
print(result)
generate_coap_resources()
print(result)

0 comments on commit 8a3f5e1

Please sign in to comment.