diff --git a/next.py b/next.py index c4380ec..4b754e7 100644 --- a/next.py +++ b/next.py @@ -39,13 +39,11 @@ def log(txt): print("[-] "+str(txt)) def sendEmOff(bundles, api): - print("SENDING (") - pprint(bundles) - print(")") - return - api.send_trytes( - trytes=bundles - ) + print("[->]") + for bundle in bundles: + api.send_trytes( + trytes=bundle + ) class Atom(): def __init__(self, milestone: bool, cont, name: str = None) -> None: @@ -133,7 +131,7 @@ class TangleBlob(): def dumpAllSealed(self): bundles = [] - for i in range(len(self.chunks)-self.pushedNum): + for i in range(max(0,len(self.chunks)-self.pushedNum)): c = i + self.pushedNum chunk = self.chunks[c] if chunk.isSealed(): @@ -143,7 +141,8 @@ class TangleBlob(): def sealAndDump(self): # When unmounting / closing / ... - self.chunks[-1].seal() + if self.chunks: + self.chunks[-1].seal() return self.dumpAllSealed() def append(self, data: bytes, newBlock: bool = False) -> None: @@ -174,6 +173,7 @@ class TangleBlob(): return self.preChunks def read(self) -> bytes: + self._requireFetched() data = b'' for chunk in self.chunks: data += chunk.getData() @@ -198,7 +198,7 @@ class TangleBlob(): txHash = self.iotaApi.find_transactions(tags=[Tag("IOTAFS")], addresses=[addr])["hashes"] if len(txHash)==0: break - bundles = self.api.get_bundles(txHash[0])["bundles"] + bundles = self.iotaApi.get_bundles(txHash[0])["bundles"] for bundle in bundles: for tx in bundle.transactions: # TODO: Can we just strip the 9s and call it a day? @@ -236,7 +236,7 @@ class TangleBlob(): lines[-1]+=" {+}" return "\n".join(lines) - def close(self): + def _close(self): bundles = self.sealAndDump() if bundles: sendEmOff(bundles, self.iotaApi) @@ -260,7 +260,7 @@ class TangleFileTreeElement(TangleBlob): return unpacker = msgpack.Unpacker(raw=True) unpacker.feed(raw) - for i, elem in enumerate(reversed(unpacker)): + for i, elem in enumerate(reversed(list(unpacker))): if elem[0]: # Is a milestone # TODO: Update our known milestoneIndex, if we find one @@ -269,12 +269,16 @@ class TangleFileTreeElement(TangleBlob): self._applyMilestone(elem[1]) break else: - if elem[1] in self.inodes: #name - self.inodes[elem[1]].applyDelta(elem[2]) + name = elem[1].decode() + if name in self.inodes: #name + atom = Atom(False, elem[2], name) + self.inodes[name].applyAtom(atom) else: - # new file - self.inodes[elem[1]] = Inode(elem[1], self.iotaApi) - self.inodes[elem[1]].applyDelta(elem[2]) + # new inode + type = ["dir","file"][elem[2][b't']] + self.inodes[name] = Inode(name, self.iotaApi, self, type) + atom = Atom(False, elem[2], name) + self.inodes[name].applyAtom(atom) def _getSkipChunks(self): return @@ -303,6 +307,7 @@ class TangleFileTreeElement(TangleBlob): return list(self.inodes.keys()) def _tree(self): + self._requireFetched() dirs = {} files = [] for inode in self.inodes: @@ -358,15 +363,14 @@ class TangleFileTreeElement(TangleBlob): def _updateFileSize(self, name: str, size: int) -> None: self._requireFetched() - self.inodes[name].size = size - self._newAtom(self.inodes[name]) + atom = self.inodes[name].change(size=size) + self._newAtom(atom) - def _updateFileToken(self, name: str, token: bytes, size: int) -> None: + def _updateFileHash(self, name: str, hash: bytes, size: int) -> None: log("New FileToken for file '"+name+"' registered") self._requireFetched() - self.inodes[name].token = token - self.inodes[name].size = size - self._newAtom(self.inodes[name]) + atom = self.inodes[name].change(size=size, hash=hash) + self._newAtom(atom) def performMilestone(self) -> None: if isinstance(self.parent, bytes): @@ -375,45 +379,58 @@ class TangleFileTreeElement(TangleBlob): for a in self.inodes: stones[a] = self.inodes[a].toStone() self.atomStack = 0 - # TODO: Delimiter ? - # TODO: compression ? milestoneAtom = Atom(True, stones) data = milestoneAtom.dump() - self.milestoneIndex = self.getSize() + self.milestoneIndex = self.getChunkLen() if self.parent!=None: self.parent._updateChildMilestone(self.name, self.milestoneIndex) self.append(data, True) def _updateChildMilestone(self, name: str, milestoneIndex: int): + atom = self.inodes[name].change(milestoneIndex = milestoneIndex) if isinstance(self.parent, bytes): # We are the genesis-block - self.append(milestoneIndex) + self.milestoneIndex = milestoneIndex + self.append(msgpack.dumps(milestoneIndex)) else: - atom = self.inodes[name].change(milestoneIndex = milestoneIndex) self._newAtom(atom) + def close(self) -> None: + for i in self.inodes: + inode = self.inodes[i] + if inode.hasRef: + ref = inode.getRef() + ref.close() + self._close() + class TangleFile(): def __init__(self, name: str, parent: TangleFileTreeElement, iotaApi: Iota) -> None: self.api = iotaApi self.name = name self.parent = parent - self.reflexiveAtom = parent.inodes[name] - self.size = self.reflexiveAtom.size - self.hash = self.reflexiveAtom.hash - self.token = hashlib.sha3_384(b'f' + parent.getRef().token + self.hash).digest() + self.reflexiveInode = parent.inodes[name] + self.size = self.reflexiveInode.size + self.hash = self.reflexiveInode.hash + self.token = hashlib.sha3_384(b'f' + parent.token + self.hash).digest() self.blob = TangleBlob(self.token, iotaApi) def write(self, offset: int, data: bytes): if offset == self.size: - self.append(data) + self.blob.append(data) + self.size = self.blob.getSize() + self.parent._updateFileSize(self.name, self.size) else: - self.token = self.genToken() oldData = self.blob.read() newData = oldData[:offset] + data + oldData[offset+len(data):] + self.hash = hashlib.sha256(newData).digest() + self.token = hashlib.sha3_384(b'f' + self.parent.token + self.hash).digest() self.blob = TangleBlob(self.token) self.blob.append(newData) self.size = self.blob.getSize() - self.parent._updateFileToken(self.name, self.token, self.size) + self.parent._updateFileHash(self.name, self.hash, self.size) + + def close(self): + self.blob._close() class Inode(): def __init__(self, name: str, iotaApi: Iota, parent: TangleFileTreeElement = None, type: str = None) -> None: @@ -471,11 +488,14 @@ class Inode(): if self.type=="dir": self.ref = TangleFileTreeElement(self.name, self.milestoneIndex, self.parent, self.iotaApi) elif self.type=="file": - self.ref = TangleFile(self.name, self, self.iotaApi) + self.ref = TangleFile(self.name, self.parent, self.iotaApi) else: raise Exception("Cannot get reference of an inode of type "+self.type) return self.ref + def hasRef(self): + return not self.ref==None + class IotaFs(): def __init__(self, token) -> None: self.api = Iota('https://nodes.thetangle.org:443', local_pow=True) @@ -491,35 +511,36 @@ class IotaFs(): + "Unknown records for no root-directory in Genesis Chain: "+str(self.genesis.getNameList())) else: # we dont have a root yet, lets create one... - log("Unable to reference to root: Creating new root") + log("Unable to find reference to root: Creating new root") self.genesis.mkdir("/") log("Successfully Mounted!") - def createNewFile(self, name) -> None: pass api = Iota('https://nodes.thetangle.org:443', local_pow=True) token = b'testToken' genesis = TangleFileTreeElement("*", 0, token, api) -genesis.mkdir("/") -root = genesis.inodes["/"].getRef() -root.mkdir("dir1") -root.mkdir("dir2") -root.mkdir("dir3") -root.mkdir("dir4") -root.mkfile("file.txt") -d2 = root.inodes["dir2"].getRef() -d2.mkfile("a.txt") -d3 = root.inodes["dir3"].getRef() -d3.mkfile("b.txt") -d3.mkfile("c.txt") -d3.mkfile("d.txt") -d3.mkdir("subDir") -d4 = root.inodes["dir4"].getRef() -d4.mkdir("sub") -sub = d4.inodes["sub"].getRef() -sub.mkdir("subsub") +if False: + genesis.mkdir("/") + root = genesis.inodes["/"].getRef() -print(genesis.tree()) + root.mkdir("dir1") + root.mkdir("dir2") + root.mkdir("dir3") + root.mkdir("dir4") + root.mkfile("file.txt") + d2 = root.inodes["dir2"].getRef() + d2.mkfile("a.txt") + d3 = root.inodes["dir3"].getRef() + d3.mkfile("b.txt") + d3.mkfile("c.txt") + d3.mkfile("d.txt") + d3.mkdir("subDir") + d4 = root.inodes["dir4"].getRef() + d4.mkdir("sub") + sub = d4.inodes["sub"].getRef() + sub.mkdir("subsub") + + print(genesis.tree())