Files @ 6355fe7d655f
Branch filter:

Location: Morevna/src/server.py - annotation

Laman
fix server hash tree update for real
import hashlib
import socket
import logging as log

from hashtree import HashTree
from networkers import NetworkReader,NetworkWriter
import config as conf


class Connection:
	def __init__(self,serverSocket):
		self._socket, address = serverSocket.accept()
		log.info('Connected by {0}'.format(address))
		fr=self._socket.makefile(mode="rb")
		fw=self._socket.makefile(mode="wb")

		self.incoming=NetworkReader(fr)
		self.outcoming=NetworkWriter(fw)

	def __enter__(self):
		return self.incoming,self.outcoming

	def __exit__(self, exc_type, exc_val, exc_tb):
		self._socket.close()


class Server:
	def __init__(self,filename,treeFile=""):
		self._filename=filename
		self._treeFile=treeFile

		if treeFile:
			self._tree=HashTree.load(treeFile)
		else:
			self._tree=HashTree.fromFile(filename)

		self._newLeaves=dict()
		self.BLOCK_SIZE=self._tree.BLOCK_SIZE

		self._ss = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		self._ss.bind(("", conf.port))
		self._ss.listen(1)

		self._lastWrite=-1
		self._dataFile=None

	def serve(self):
		while True:
			with Connection(self._ss) as (incoming, outcoming):
				try:
					while True:
						if not self._serveOne(incoming,outcoming): return
				except AssertionError:
					continue

	def _serveOne(self,incoming,outcoming):
		jsonData,binData=incoming.readMsg()

		if jsonData["command"]=="init":
			assert jsonData["blockSize"]==self.BLOCK_SIZE
			assert jsonData["blockCount"]==self._tree.leafCount
			outcoming.writeMsg({"command": "ack"})

		elif jsonData["command"]=="req":
			outcoming.writeMsg(*self._requestHash(jsonData))

		elif jsonData["command"]=="send" and jsonData["dataType"]=="data":
			outcoming.writeMsg(*self._receiveData(jsonData,binData))

		elif jsonData["command"]=="end":
			self._finalize()
			return False

		else:
			assert False, jsonData["command"]

		return True

	def _requestHash(self,jsonData):
		log.info("received request for node #{0}".format(jsonData["index"]))
		assert jsonData["index"]<len(self._tree.store)
		nodeHash=self._tree.store[jsonData["index"]]

		jsonResponse={"command":"send", "index":jsonData["index"], "dataType":"hash"}
		binResponse=nodeHash

		return (jsonResponse,binResponse)

	def _receiveData(self,jsonData,binData):
		log.info("received data block #{0}: {1}...{2}".format(jsonData["index"],binData[:5],binData[-5:]))

		if not self._dataFile:
			self._dataFile=open(self._filename, mode="rb+")
		i=jsonData["index"]
		if self._lastWrite+1!=i:
			self._dataFile.seek(i * self.BLOCK_SIZE)
		self._dataFile.write(binData)
		self._lastWrite=i
		if self._treeFile:
			self._newLeaves[i + self._tree.leafStart]= hashlib.sha256(binData).digest()[HashTree.HASH_LEN:]

		return ({"command": "ack", "index": i},)

	def _finalize(self):
		log.info("closing session...")
		if self._dataFile:
			self._dataFile.close()
		if self._treeFile:
			log.info("updating hash tree...")
			for (k,v) in self._newLeaves.items():
				self._tree.updateLeaf(k, v)
			self._tree.save(self._treeFile)
		log.info("done")