diff --git a/simu/data/subscriptions.csv b/simu/data/subscriptions.csv new file mode 100644 index 0000000000000000000000000000000000000000..b7cc6dae614e9fccd0600d3f5b90fcbe6f7f0b1d --- /dev/null +++ b/simu/data/subscriptions.csv @@ -0,0 +1 @@ +subscription_id,corr_id,address,callback,ue_event_criteria,resourceURL diff --git a/simu/mec_database.py b/simu/mec_database.py index bb38d31a2300b8744096eb893de27a30c7303a22..c4f5ce5c3eb10e034b8f75aa9e4f952ed16b8ff5 100644 --- a/simu/mec_database.py +++ b/simu/mec_database.py @@ -5,7 +5,7 @@ from datetime import datetime, time class mec_database: """ Private properties """ - __path__ = "/Users/yanng/OneDrive/Documents/Python/Mec/data/" # To be updated according to the local settings + __path__ = "/Users/yanng/Documents/workspace_titan/STF569_Mec/simu/data/" # To be updated according to the local settings __subscribers__ = None __registered_list__ = None __zones__ = None @@ -14,6 +14,7 @@ class mec_database: __location_info__ = None __cells__ = None __associated__ = None + __subscribions__ = None def __init__(self): """ Default ctor: Open Pandas database. """ @@ -24,6 +25,7 @@ class mec_database: self.__location_info__ = pd.DataFrame(pd.read_csv(self.__path__ + 'location_info.csv', index_col = 'accessPointId')) self.__cells__ = pd.DataFrame(pd.read_csv(self.__path__ + 'cells.csv', encoding = 'utf-8', index_col = 'cellId')) self.__associated__ = pd.DataFrame(pd.read_csv(self.__path__ + 'associated.csv', encoding = 'utf-8', index_col = 'cellId')) + self.__subscriptions__ = pd.DataFrame(pd.read_csv(self.__path__ + 'subscriptions.csv', encoding = 'utf-8', index_col = 'subscription_id')) #self.dump() # End of __init__ @@ -36,10 +38,16 @@ class mec_database: print("LocationInfo: ", self.__location_info__.head()) print("Cells: ", self.__cells__.head()) print("Associated: ", self.__associated__.head()) + print("subscriptions: ", self.__subscribions__.head()) # End of dump def __to_accessPoint__(self, p_access_point, p_location): - """ Build an AccessPointLocation Json message. """ + """ + Build an AccessPointLocation Json message. + Keyword arguments: + -- p_access_point: Access point identifier + -- p_location : Access point geographical location + """ print(">>> __to_accessPoint__: ", p_access_point) print("__to_accessPoint__: location= ", p_location['latitude'][0]) i = 0.0 @@ -56,7 +64,11 @@ class mec_database: # End of __to_accessPoint__ def __to_zone__(self, p_zone): - """ Build a Zones Json message. """ + """ + Build a Zones Json message. + Keyword arguments: + -- p_zone: Zone description + """ print(">>> __to_zone__: ", p_zone) resp = "{\t\"zoneId\": \"" + p_zone[0] + "\",\t\"numberOfAccessPoints\": \"" + str(p_zone[1]) + "\",\t\"numberOfUnserviceableAccessPoints\": \"" + str(p_zone[2]) + "\",\t\"numberOfUsers\": \"" + str(p_zone[3]) + "\",\t\"resourceURL\": \"" + p_zone[4] + "\"}" print("__to_zone__: ", resp) @@ -79,6 +91,21 @@ class mec_database: return resp # End of __to_ueIdentityTagInfo__ + def __to_subscriptions__(self, p_subscription): + """ Build the userTrackingSubscription response """ + print(">>> __to_subscriptions__: ", p_subscription) + resp = "\t{\"userTrackingSubscription\": {\t\"clientCorrelator\": \"" + p_subscription[1] + "\",\t\"callbackReference\": {\"notifyURL\": \"" + p_subscription[3] + "\"},\t\"address\": \"" + p_subscription[2] + "\",\t\"userEventCriteria\" : [" + resp += "\"" + p_subscription[4][0] + "\"" + i = 1 + while i < len(p_subscription[4]): + resp += ",\"" + p_subscription[4][i] + "\"" + i += 1 + # End of 'while' statement + resp += "],\t\"resourceURL\":\"" + p_subscription[5] + "\"\t}}" + print("__to_subscriptions__: ", resp) + return resp + # End of __to_subscriptions__ + def getSubscriberList(self, p_uri): """ Build a SubscriberList Json message. """ print(">>> getSubscriberList") @@ -199,6 +226,43 @@ class mec_database: return resp # End of method registerUEidentity + def registerSubscription(self, p_json_msg, p_uri): + print(">>> registerSubscription: ", p_json_msg, "/", p_uri) + resp = None + subscription_id = "subscription" + p_json_msg["clientCorrelator"] + try: + # Check the record does not exist + self.__subscriptions__.loc[self.__subscriptions__['subscription_id'] == subscription_id] + print("registerSubscription: There is a subscription for ", subscription_id) + except KeyError: + #print("registerSubscription: Add new row in subscription") + resource_url = "http://example.com" + p_uri + "/" + subscription_id + row = pd.Series({ 'subscription_id': subscription_id, 'corr_id': p_json_msg["clientCorrelator"], 'address': p_json_msg["address"], 'callback': p_json_msg["callbackReference"]["notifyURL"], 'ue_event_criteria': p_json_msg["userEventCriteria"], 'resourceURL': resource_url }) + #print("registerSubscription: row: ", row) + self.__subscriptions__ = self.__subscriptions__.append(row, ignore_index=True).reindex() + #print("registerSubscription: ", self.__subscriptions__.head()) + r = tuple(self.__subscriptions__.loc[self.__subscriptions__['subscription_id'] == subscription_id].to_records()) + #print("registerSubscription: New added row: ", r[0]) + resp = self.__to_subscriptions__(r[0]) + return resp + # End of registerSubscription + + def unregisterSubscription(self, p_subscription_id): + print(">>> unregisterSubscription: ", p_subscription_id) + resp = None + try: + # Check the record exists + r = self.__subscriptions__.loc[self.__subscriptions__['subscription_id'] == p_subscription_id] + t = tuple(r.to_records()) + print("unregisterSubscription: Find row: ", t) + resp = self.__to_subscriptions__(t[0]) + # Remove it + self.__subscriptions__.drop(r.index) + except KeyError: + print("unregisterSubscription: No subscription for ", p_subscription_id) + return resp + # End of unregisterSubscription + def getBwAllocationAppInst(self, p_app_inst, p_ue_identity_tag): print(">>> getBwAllocationAppInst: ", p_app_inst, ", ", p_ue_identity_tag) resp = None diff --git a/simu/mec_http_server.py b/simu/mec_http_server.py index 65e16662509b4dfd5375de1d536200f7d52fb29c..5ff43fd5130d3b0780eca7ed3977a2eb076248a3 100644 --- a/simu/mec_http_server.py +++ b/simu/mec_http_server.py @@ -8,7 +8,7 @@ class myHandler(http.server.BaseHTTPRequestHandler): # Handler for the GET requests def do_GET(self): - print(">>> do_GET: ", self.path) + print('>>> do_GET: ', self.path) self.protocol_version = self.request_version # Check HTTP end_headers if self.__check_http_headers__() == False: @@ -16,7 +16,7 @@ class myHandler(http.server.BaseHTTPRequestHandler): self.send_response(400, 'Bad Request') self.send_header('Host', self.headers.get('Host')) self.send_header('Authorization', self.headers.get('Authorization')) - self.send_header('Content-Type', "application/problem+json") + self.send_header('Content-Type', 'application/problem+json') l = len(resp) self.send_header('Content-Length', str(l)) self.end_headers() @@ -24,7 +24,7 @@ class myHandler(http.server.BaseHTTPRequestHandler): return resp, content_type = self.__process__() - print("do_GET: resp= ", resp, ", Content_Type= ", content_type) + print('do_GET: resp= ', resp, ', Content_Type= ', content_type) if (resp == None): self.send_response(404, 'Not Found') self.send_header('Host', self.headers.get('Host')) @@ -61,7 +61,7 @@ class myHandler(http.server.BaseHTTPRequestHandler): self.send_response(400, 'Bad Request') self.send_header('Host', self.headers.get('Host')) self.send_header('Authorization', self.headers.get('Authorization')) - self.send_header('Content-Type', "application/problem+json") + self.send_header('Content-Type', 'application/problem+json') l = len(resp) self.send_header('Content-Length', str(l)) self.end_headers() @@ -69,7 +69,7 @@ class myHandler(http.server.BaseHTTPRequestHandler): return resp, content_type = self.__process__() - print("do_POST: resp= ", resp, ", Content_Type= ", content_type) + print('do_POST: resp= ', resp, ', Content_Type= ', content_type) if (resp == None): self.send_response(404, 'Not Found') self.send_header('Host', self.headers.get('Host')) @@ -84,6 +84,8 @@ class myHandler(http.server.BaseHTTPRequestHandler): self.send_response(403, 'Forbidden') elif resp.find('Bad Request') != -1: self.send_response(400, 'Bad Request') + elif resp.find('userTrackingSubscription') != -1: + self.send_response(201, 'Created') else: self.send_response(200, 'OK') self.send_header('Host', self.headers.get('Host')) @@ -98,14 +100,14 @@ class myHandler(http.server.BaseHTTPRequestHandler): # Check HTTP headers def __check_http_headers__(self): - print (">>> __check_http_headers__") + print('>>> __check_http_headers__') result = True host = self.headers.get('Host') if host == None: - print("__check_http_headers__: Failed to parse 'Host' header") + print("__check_http_headers__: Failed to parse Host header") result = False content_type = self.headers.get('Content-Type') - if content_type != "application/json": + if content_type != 'application/json': print("__check_http_headers__: Failed to parse 'Content-Type' header") result = False auth = self.headers.get('Authorization') @@ -118,9 +120,9 @@ class myHandler(http.server.BaseHTTPRequestHandler): # Process the request def __process__(self): s = self.path.split('/') - print (">>> __process__: ", s) + print('>>> __process__: ', s) if s[1] != 'exampleAPI': - return None, "application/json" + return None, 'application/json' # TODO Check HTTP headers if s[2] == 'location' and ((s[3] == 'v1') or (s[3] == 'v2')): return self.__process__location__api__(s) @@ -131,14 +133,14 @@ class myHandler(http.server.BaseHTTPRequestHandler): elif s[2] == 'bwm' and ((s[3] == 'v1') or (s[3] == 'v2')): return self.__process__bwm__api__(s) else: - return None, "application/json" + return None, 'application/json' # End of __process__ # Process the LocationAPI request def __process__location__api__(self, p_split): print (">>> __process__location__api__: ", p_split) resp = None - content_type = "application/json" + content_type = 'application/json' if p_split[4].startswith('users'): # E.g. users?zoneId=zone01 s = p_split[4].split('?') if s.__len__() == 1: # Users list requested @@ -169,6 +171,20 @@ class myHandler(http.server.BaseHTTPRequestHandler): resp = "{\"Unsupported " + p_split[5] + " request\"}" else: resp = "{\"Unsupported " + p_split[4] + " request\"}" + elif p_split[4] == 'subscriptions': + if p_split.__len__() == 6: + # Extract the body if any + body = None + content_len = int(self.headers.get('Content-Length')) + if (content_len != 0): + body = self.rfile.read(content_len) + json_msg = self.__decode__json__body__(body) + if (json_msg == None): + resp = "{\"problemDetails\": {\t\"type\": \"Body processing not supported\",\t\"title\": \"UElocationAPI\",\t\"status\": 400,\t\"detail\": \"Unknown request\",\t\"instance\": \"string\"}}" + else: + resp = self.__db__.registerSubscription(json_msg, self.path) + elif p_split.__len__() == 7: + resp = self.__db__.unregisterSubscription(p_split[6]) else: resp = "{\"Unsupported " + p_split[4] + " request\"}" @@ -180,7 +196,7 @@ class myHandler(http.server.BaseHTTPRequestHandler): def __process__ue__identity__api__(self, p_split): print (">>> __process__ue__identity__api__: ", p_split) resp = None - content_type = "application/json" + content_type = 'application/json' if p_split[4] == 'appInst98': # Used for unknown application, e.g. TC_MEC_PLAT_UETAG_003_BI resp = "{\"problemDetails\": {\t\"type\": \"Not Authorized\",\t\"title\": \"UEidentityAPI\",\t\"status\": 403,\t\"detail\": \"Forbidden\",\t\"instance\": \"AppInst98\"}}" else: @@ -206,12 +222,12 @@ class myHandler(http.server.BaseHTTPRequestHandler): resp = self.__db__.getUEidentityTagInfo(p_split[4], s[1]) if (resp == None): resp = "{\"problemDetails\": {\t\"type\": \"Not Found\",\t\"title\": \"UEidentityAPI\",\t\"status\": 404,\t\"detail\": \"Wrong parameters\",\t\"instance\": \"string\"}}" - content_type = "application/problem+json" + content_type = 'application/problem+json' if (resp == None): resp = "{\"problemDetails\": {\t\"type\": \"Bad Request\",\t\"title\": \"UEidentityAPI\",\t\"status\": 400,\t\"detail\": \"Wrong parameters\",\t\"instance\": \"string\"}}" - content_type = "application/problem+json" + content_type = 'application/problem+json' elif resp.find('problemDetails') != -1: - content_type = "application/problem+json" + content_type = 'application/problem+json' print ("<<< __process__ue__identity__api__: ", resp, ", ", content_type) return resp, content_type @@ -219,16 +235,16 @@ class myHandler(http.server.BaseHTTPRequestHandler): # Process the RnisAPI request def __process__rnis__api__(self, p_split): - print (">>> __process__rnis__api__: ", p_split) + print ('>>> __process__rnis__api__: ', p_split) resp = None - content_type = "application/json" + content_type = 'application/json' if p_split[4].startswith('subscriptions'): if p_split.__len__() == 6: if p_split[5] == '': resp = self.__db__.getSubscriptionLinkList(self.path) if (resp == None): resp = "{\"problemDetails\": {\t\"type\": \"Not supported\",\t\"title\": \"RnisAPI\",\t\"status\": 400,\t\"detail\": \"Wrong parameters\",\t\"instance\": \"string\"}}" - content_type = "application/problem+json" + content_type = 'application/problem+json' print ("<<< __process__rnis__api__: ", resp, ", ", content_type) return resp, content_type @@ -238,7 +254,7 @@ class myHandler(http.server.BaseHTTPRequestHandler): def __process__bwm__api__(self, p_split): print (">>> __process__bwm__api__: ", p_split) resp = None - content_type = "application/json" + content_type = 'application/json' if p_split[4].startswith('bw_allocations'): # E.g. bw_allocation?app_instance_id=InstApp01 s = p_split[4].split('?') if s.__len__() == 1: # ue_identity_tag_info, POST @@ -251,7 +267,7 @@ class myHandler(http.server.BaseHTTPRequestHandler): json_msg = self.__decode__json__body__(body) if (json_msg == None): resp = "{\"problemDetails\": {\t\"type\": \"Body processing not supported\",\t\"title\": \"BwManagementAPI\",\t\"status\": 400,\t\"detail\": \"Unknown request\",\t\"instance\": \"string\"}}" - content_type = "application/problem+json" + content_type = 'application/problem+json' else: resp = self.__db__.bwAllocation(json_msg) elif s.__len__() == 2: # E.g. app_instance_id=InstApp01 @@ -260,7 +276,7 @@ class myHandler(http.server.BaseHTTPRequestHandler): resp = self.__db__.getBwAllocationAppInst(p_split[4], s[1]) if (resp == None): resp = "{\"problemDetails\": {\t\"type\": \"Not supported\",\t\"title\": \"BwManagementAPI\",\t\"status\": 400,\t\"detail\": \"Wrong parameters\",\t\"instance\": \"string\"}}" - content_type = "application/problem+json" + content_type = 'application/problem+json' print ("<<< __process__bwm__api__: ", resp, ", ", content_type) return resp, content_type @@ -268,11 +284,15 @@ class myHandler(http.server.BaseHTTPRequestHandler): # Decode a Json HTTP body message def __decode__json__body__(self, p_body): + print(">>> __decode__json__body__: ", p_body) json_msg = json.loads(p_body) print("__decode__json__body__: ", type(json_msg)) - if ("ueIdentityTags" in json_msg.keys()) == False: - return None - return json_msg.get("ueIdentityTags")[0] + print("__decode__json__body__: ", json_msg.keys()) + if ("ueIdentityTags" in json_msg.keys()) == True: + return json_msg.get("ueIdentityTags")[0] + elif ("userTrackingSubscription" in json_msg.keys()) == True: + return json_msg.get("userTrackingSubscription") + return None # End of __decode__json__body__ # End of class SimpleHTTPRequestHandler diff --git a/simu/mec_simulator.py b/simu/mec_simulator.py index 7540eda59936b85bd62c8dd14622e1e56a640eb7..1d2a11837045f71c05a971efef199606ac8e37df 100644 --- a/simu/mec_simulator.py +++ b/simu/mec_simulator.py @@ -30,7 +30,7 @@ if __name__ == '__main__': # Wait forever for incoming http requests in background #server.serve_forever() threading.Thread(target=server.serve_forever).start() - # Use keybord entries to trigger notifications + # Use keybord entries to trigBger notifications while exit == False: ch = getch() if ch == b'\x03':