-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmutualStore.py
More file actions
125 lines (119 loc) · 4.9 KB
/
mutualStore.py
File metadata and controls
125 lines (119 loc) · 4.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import connection as CON
import diskUtils as DISK
import disHash as CHORD
import encode
import sys
import os
import time
import socket
#Index of files stored to the network
fileIndex = []
#This class defines the entries of the file index
class indexEntry():
def __init__(self, fileName, keys, checkSumKey):
self.fileName = fileName
self.keys = keys
self.checkSumKey = checkSumKey
def storeFile(fileName):
#initializes a list of keys to be stored in the index
keys = []
#initializes a bytearray for storing the contents of the local file
data = bytearray()
#Opens the file and stores it in data
with open(fileName, 'rb') as file:
byte = file.read(1)
while byte:
data.append(byte[0])
byte = file.read(1)
#initializes a bytearray to store a blocks worth of data
a = 0
#breaks the data into blocks and sends them to the server to be stored
numBlocks = encode.round(float(len(data)) / float(DISK.blockSize))
for n in range(numBlocks):
block = bytearray(DISK.blockSize)
for i in range(DISK.blockSize):
a = n * DISK.blockSize + i
if a < len(data):
block[i] = data[a]
else:
break
#creates a hash of the block to serve as a key to determine where it should be stored
key = CHORD.hash(block)
#connects to local server to start the process
stub = CON.initializeClientConnection('127.0.0.1')
#appends the key returned to the list of keys for the file index
keys.append(stub.StoreBlock(CON.MESSAGE.StoreReq(key = key, data = bytes(block))).status)
#Creates checksum block and stores it on the network
checksum = encode.encode(data)
key = CHORD.hash(checksum)
stub = CON.initializeClientConnection('127.0.0.1')
checkSumKey = stub.StoreBlock(CON.MESSAGE.StoreReq(key = key, data = bytes(checksum))).status
#adds filename and list of keys to file index
fileIndex.append(indexEntry(fileName, keys, checkSumKey))
def retrieveFile(fileName):
#creates a data bucket for the data retrieved from the network
data = bytearray()
checksum = bytearray(DISK.blockSize)
missingBlock = -1
#searches the fileIndex for the filename
for a in fileIndex:
if a.fileName == fileName:
bc = 0
blocks = [bytearray(DISK.blockSize)] * len(a.keys)
#if the filename is found in the index, iterate over the keys in the index to retrieve each block of data
for i in a.keys:
stub = CON.initializeClientConnection('127.0.0.1')
#This causes block 4 to fail, to test the ability to recover
if bc != 4:
blocks[bc] = bytearray(stub.RetrieveBlock(CON.MESSAGE.RetrieveReq(key = i),timeout = 10).data)
data += blocks[bc]
else:
missingBlock = 4
bc += 1
time.sleep(.5)
#if there is a missing block
if missingBlock > -1:
print("Recovering missing block number " + str(missingBlock))
time.sleep(6)
stub = CON.initializeClientConnection('127.0.0.1')
#get the checksum from network storage
checksum = bytearray(stub.RetrieveBlock(CON.MESSAGE.RetrieveReq(key = a.checkSumKey)).data)
#decode the missing block using the other blocks and the checksum
blocks[missingBlock] = encode.decode(data, checksum)
#build the file with the missing block in the correct position
data2 = bytearray()
for a in blocks:
data2 += a
return data2
#if no missing blocks return data, else return data2
return data
def deleteFile(fileName):
#iterates over all files in the index to find the filename
for a in fileIndex:
if a.fileName == fileName:
#if the filename is found iterates over each block to unmute the nodes
for i in a.keys:
stub = CON.initializeClientConnection('127.0.0.1')
stub.DeleteBlock(CON.MESSAGE.DeleteReq(key = i))
if __name__ == "__main__":
DISK.fdisk()
#forks the client and server runtimes
pid = os.fork()
if(pid == 0):
time.sleep(2)
#discovers peers
CON.createConnections()
time.sleep(1)
#if the user uses the store or load options determines the behaviour of the program
if(len(sys.argv) > 1):
if(sys.argv[1] == 'store'):
#For testing client1 stores a file and then retrieves it
if(socket.gethostname() == "client1"):
storeFile(sys.argv[2])
time.sleep(5)
print(retrieveFile(sys.argv[2]).decode('utf-8'))
if(sys.argv[1] == 'load'):
retrieveFile(sys.argv[2])
else:
#Start server
CON.initializeServerConnection()