Skip to content

Commit ff7befa

Browse files
committedJul 22, 2020
Documented server.py
1 parent bdc7e8c commit ff7befa

File tree

1 file changed

+67
-7
lines changed

1 file changed

+67
-7
lines changed
 

‎backend-contact-tracing/server.py

+67-7
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,17 @@
1010
import pandas as pd
1111
from sklearn.cluster import DBSCAN
1212

13-
13+
# API configurations
1414
app = flask.Flask(__name__)
1515
CORS(app)
1616
app.config["DEBUG"] = True
1717

18+
# Defining some of the commonly used constants for interaction with Blockchain
1819
blockchain_url = 'https://kovan.infura.io/v3/' + \
1920
os.environ['WEB3_INFURA_PROJECT_ID']
2021
abi = """[{"anonymous": false,"inputs": [{"indexed": false,"internalType": "address","name": "deviceID","type": "address"},{"indexed": false,"internalType": "string","name": "latestCID","type": "string"}],"name": "MappingUpdated","type": "event"},{"inputs": [{"internalType": "address","name": "deviceID","type": "address"},{"internalType": "string","name": "latestCID","type": "string"}],"name": "setLatestCID","outputs": [],"stateMutability": "nonpayable","type": "function"},{"inputs": [],"name": "getDeviceIDsLength","outputs": [{"internalType": "uint256","name": "","type": "uint256"}],"stateMutability": "view","type": "function"},{"inputs": [{"internalType": "uint256","name": "index","type": "uint256"}],"name": "getIDByIndex","outputs": [{"internalType": "address","name": "","type": "address"}],"stateMutability": "view","type": "function"},{"inputs": [{"internalType": "address","name": "deviceID","type": "address"}],"name": "getLatestCID","outputs": [{"internalType": "string","name": "latestCID","type": "string"}],"stateMutability": "view","type": "function"}]"""
2122

23+
# Defining some of the commonly used constants for interaction with MoiBit
2224
conn = http.client.HTTPSConnection("kfs2.moibit.io")
2325
moibit_url = 'https://kfs2.moibit.io/moibit/v0/'
2426
moibit_header_obj = {
@@ -27,47 +29,75 @@
2729
'content-type': "application/json"
2830
}
2931

30-
32+
# Defining the root endpoint
3133
@app.route('/', methods=['GET'])
3234
def home():
3335
return "<h1>DICTAO - Decentralized Intelligent Contact Tracing of Animals and Objects</h1><p>This is a simple demonstration of applying blockchain, decentralized storage and AI to solve the COVID-19 crisis.</p>"
3436

3537

38+
# Defining the HTTP 404 response
3639
@app.errorhandler(404)
3740
def page_not_found(e):
3841
return "The given ID could not be found", 404
3942

4043

44+
# Defining the HTTP 500 response
4145
@app.errorhandler(500)
4246
def internal_server_error(e):
4347
return e, 500
4448

4549

50+
# Defining the main endpoint
4651
@app.route('/api/v0/get_infections', methods=['GET'])
4752
def get_infections():
4853
masterDataSet = []
54+
# Extracting the input parameters sent by the API calling client
4955
query_parameters = request.args
56+
57+
# Scanning for the input parameter named 'id'
5058
if 'id' in query_parameters:
59+
# Reading the value attached to the query parameter 'id'
5160
id = query_parameters.get('id')
5261
print("Received ID from the user: "+id)
62+
63+
# Checking if the value of 'id' query parameter is null
5364
if getLatestCID(id) == "":
65+
# Since no value was passed to 'id', we are returning 404
5466
return page_not_found(404)
5567
else:
68+
# Initiating the web3 object
5669
w3 = Web3(Web3.HTTPProvider(blockchain_url))
70+
71+
# Loading the contract object based on the contract address and ABI
5772
contract = w3.eth.contract(
5873
os.environ['PROOF_SMART_CONTRACT_ADDRESS'], abi=abi)
74+
75+
# Calling the smart contract function getDeviceIDsLength() in the smart contract
5976
length = contract.functions.getDeviceIDsLength().call()
6077
print("Length of the deviceIDs: "+str(length))
6178
for i in range(length):
79+
# Read the ID/Wallet Address from the contract
6280
tempId = contract.functions.getIDByIndex(i).call()
63-
# print(tempId)
81+
82+
# Read the latest CID of the corresponding ID
6483
tempHash = contract.functions.getLatestCID(tempId).call()
65-
# print(tempHash)
84+
85+
# Based on the CID, download the latest location history from MoiBit
6686
jsonData = getJsonDataFromMoiBit(tempHash)
67-
# print(jsonData)
87+
88+
'''
89+
Append each location update to a dataset, so that we obtain one monolithic dataset
90+
that contains the location history of all the sensors
91+
'''
6892
for location in jsonData:
6993
masterDataSet.append(location)
94+
'''
95+
With the location history of each sensor downloaded and extracted,
96+
let us print the complete dataset
97+
'''
7098
print("Generated live dataset of length: %d" % len(masterDataSet))
99+
100+
# Write the data into a JSON file named "live_dataset.json"
71101
try:
72102
with open('live_dataset.json', 'x') as outfile:
73103
json.dump(masterDataSet, outfile, indent=2)
@@ -76,36 +106,59 @@ def get_infections():
76106
print("File Removed!")
77107
with open('live_dataset.json', 'x') as outfile:
78108
json.dump(masterDataSet, outfile, indent=2)
109+
110+
# Send the received input ID to identify potential infections
79111
results = get_infected_ids(id)
112+
113+
# With the results obtained, remove the live dataset from the server
80114
os.remove("live_dataset.json")
115+
116+
# Build the response object which consists of the input ID and the potentially infected IDs
81117
response = {
82118
"id": id,
83119
"potential_infected_ids": results
84120
}
121+
122+
# Return the JSON data as a response back to the client
85123
return (jsonify(response))
86124
else:
87125
return "Error: Please specify an ID to identify potential infections."
88126

89127

128+
'''
129+
get_infected_ids is the function used to identify any potential infections
130+
made by the given ID. It returns a list of IDs that might be infected by the given ID.
131+
'''
90132
def get_infected_ids(input_id):
133+
# Reading the live dataset by the file
91134
basePath = os.path.dirname(os.path.abspath('live_dataset.json'))
92135
dflive = pd.read_json(basePath + '/' + 'live_dataset.json')
93136

137+
# Setting some of the parameters for running DBSCAN algorithm to cluster the datapoints
94138
epsilon = 0.0018288 # a radial distance of 6 feet, which is medically presribed
95-
min_sample = 2
139+
min_sample = 2 # Suggesting that a cluster needs to contain a minimum of 2 IDs
140+
141+
# Defining the DBSCAN model for clustering the datapoints by passing the parameters and the lat-long input
96142
model = DBSCAN(eps=epsilon, min_samples=min_sample, metric='haversine').fit(dflive[['latitude', 'longitude']])
143+
144+
# Updating the dataset with the cluster ID for each datapoint
97145
dflive['cluster'] = model.labels_.tolist()
98146

147+
# Initiating an array for listing all the cluster IDs
99148
input_id_clusters = []
149+
150+
# Scanning the updated dataset for a list of unique cluster IDs
100151
for i in range(len(dflive)):
101152
if dflive['id'][i] == input_id:
102153
if dflive['cluster'][i] in input_id_clusters:
103154
pass
104155
else:
105156
input_id_clusters.append(dflive['cluster'][i])
106-
# print(input_id_clusters)
107157

158+
# Initiating the result object. We'll use this to append every potentially infected ID.
108159
infected_ids = []
160+
161+
# Scanning the updated dataset to check if other IDs exist in each cluster where the input ID already exist
109162
for cluster in input_id_clusters:
110163
if cluster != -1:
111164
ids_in_cluster = dflive.loc[dflive['cluster'] == cluster, 'id']
@@ -118,6 +171,10 @@ def get_infected_ids(input_id):
118171
return infected_ids
119172

120173

174+
'''
175+
getJsonDataFromMoiBit function is used to download the location history data
176+
for a given ID from MoiBit
177+
'''
121178
def getJsonDataFromMoiBit(cid):
122179
pre_payload = {"hash": cid}
123180
payload = json.dumps(pre_payload)
@@ -131,6 +188,9 @@ def getJsonDataFromMoiBit(cid):
131188
return responseObject
132189

133190

191+
'''
192+
getLatestCID function is used to fetch the latest CID for coressponding IDs
193+
'''
134194
def getLatestCID(id):
135195
w3 = Web3(Web3.HTTPProvider(blockchain_url))
136196
contract = w3.eth.contract(

0 commit comments

Comments
 (0)
Please sign in to comment.