Files @ 026618d6681b
Branch filter:

Location: Morevna/src/server.py

Laman
refactoring: members changed to private where possible
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.values():
				self._tree.updateLeaf(k, v)
			self._tree.save(self._treeFile)
		log.info("done")