# Path: pyledger/server/handlers.py
# def handle_request(payload: bytes):
#     """
#     Handle a single request
# 
#     :param payload: Serialized PyledgerRequest message
#     :return:
#     """
#     handler = Handler()
#     message = PyledgerRequest()
#     response = PyledgerResponse()
# 
#     try:
#         message.ParseFromString(payload)
#     except DecodeError:
#         response.successful = False
#         response.data = b'Message not properly formatted'
#         return response.SerializeToString()
# 
#     if message.request not in handler_methods(handler):
#         response.successful = False
#         response.data = 'Request type {} not available'.format(message.request).encode()
#         return response.SerializeToString()
# 
#     else:
#         # Handle authentication
#         if message.request in permissions_registry:
#             user = User.from_name(message.user)
#             permission_required = permissions_registry[message.request]
# 
#             if not user.check_password(message.password):
#                 response.successful = False
#                 response.data = b'Wrong user and/or password'
#                 return response.SerializeToString()
# 
#             if user.get_permissions().value > permission_required.value:
#                 response.successful = False
#                 response.data = b'Not enough permissions'
#                 return response.SerializeToString()
# 
#             session = Session.from_key(message.session_key)
# 
#             if not session:
#                 response.successful = False
#                 response.data = b'Session not available'
#                 return response.SerializeToString()
# 
#             if not session.user == user:
#                 response.successful = False
#                 response.data = b'Session not owned by this user'
#                 return response.SerializeToString()
# 
#             if session.until < datetime.datetime.now():
#                 response.successful = False
#                 response.data = b'Session expired, restart your client'
#                 return response.SerializeToString()
# 
#         # Select the function from the handler
#         try:
#             print('Handling message', message)
#             successful, result = getattr(handler, message.request)(message)
#         except Exception as exc:
#             successful = False
#             result = b'Exception in user function: ' + repr(exc).encode('utf-8')
# 
#         response.successful = successful
#         response.data = result
#         return response.SerializeToString()
# 
# Path: pyledger/server/contract.py
# def register_contract(contract, description=''):
#     """
#     Register a contract and make it
#     :param contract:
#     :param description:
#     :return:
#     """
#     global contract_registry
# 
#     if contract.__class__.__name__ in contract_registry:
#         raise ValueError('A contract with the same name already registered')
#     else:
#         contract_registry[contract.__class__.__name__] = contract
# 
#     db_contract = Contract()
#     db_contract.name = contract.__class__.__name__
#     db_contract.created = datetime.datetime.now()
#     db_contract.description = description
# 
#     first_status = Status()
#     first_status.contract = db_contract
#     first_status.when = datetime.datetime.now()
#     first_status.attributes = status(contract).dump()
#     # Genesis key is the name of the contract
#     first_status.key = contract.__class__.__name__.encode('utf-8')
# 
#     DB.session.add(db_contract)
#     DB.session.add(first_status)
#     DB.session.commit()
# 
# class SimpleContract(BaseContract):
#     """
#     Contract that uses SimpleStatus for serialization.
# 
#     The goal of this class is to make a contact feel just like a Python class.
#     """
#     _status_class = SimpleStatus
# 
# Path: pyledger/server/db.py
# DB = Handler()
# 
# Path: pyledger/server/auth.py
# def create_master(password):
# def create_user(name, password):
# def allow(permission):
#     def decorator(func):
# def method_allow(permission):
#     def decorator(func):


from autobahn.asyncio.websocket import WebSocketServerProtocol, \
    WebSocketServerFactory
from pyledger.server.handlers import handle_request
from pyledger.server.contract import register_contract, SimpleContract
from pyledger.server.db import DB
from pyledger.server.auth import Permissions, method_allow
import asyncio
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.



loop = asyncio.get_event_loop()


class Protocol(WebSocketServerProtocol):
    contract = None
    bcast_topic = 36*b'0'

    def onConnect(self, request):
        self.factory.register(self)
        print("Client connecting: {0}".format(request.peer))

    def onOpen(self):
        print("WebSocket connection open.")

    def onMessage(self, payload, isBinary):
        try:
            topic = payload[:36]
            payload = payload[36:]

# Path: pyledger/server/handlers.py
# def handle_request(payload: bytes):
#     """
#     Handle a single request
# 
#     :param payload: Serialized PyledgerRequest message
#     :return:
#     """
#     handler = Handler()
#     message = PyledgerRequest()
#     response = PyledgerResponse()
# 
#     try:
#         message.ParseFromString(payload)
#     except DecodeError:
#         response.successful = False
#         response.data = b'Message not properly formatted'
#         return response.SerializeToString()
# 
#     if message.request not in handler_methods(handler):
#         response.successful = False
#         response.data = 'Request type {} not available'.format(message.request).encode()
#         return response.SerializeToString()
# 
#     else:
#         # Handle authentication
#         if message.request in permissions_registry:
#             user = User.from_name(message.user)
#             permission_required = permissions_registry[message.request]
# 
#             if not user.check_password(message.password):
#                 response.successful = False
#                 response.data = b'Wrong user and/or password'
#                 return response.SerializeToString()
# 
#             if user.get_permissions().value > permission_required.value:
#                 response.successful = False
#                 response.data = b'Not enough permissions'
#                 return response.SerializeToString()
# 
#             session = Session.from_key(message.session_key)
# 
#             if not session:
#                 response.successful = False
#                 response.data = b'Session not available'
#                 return response.SerializeToString()
# 
#             if not session.user == user:
#                 response.successful = False
#                 response.data = b'Session not owned by this user'
#                 return response.SerializeToString()
# 
#             if session.until < datetime.datetime.now():
#                 response.successful = False
#                 response.data = b'Session expired, restart your client'
#                 return response.SerializeToString()
# 
#         # Select the function from the handler
#         try:
#             print('Handling message', message)
#             successful, result = getattr(handler, message.request)(message)
#         except Exception as exc:
#             successful = False
#             result = b'Exception in user function: ' + repr(exc).encode('utf-8')
# 
#         response.successful = successful
#         response.data = result
#         return response.SerializeToString()
# 
# Path: pyledger/server/contract.py
# def register_contract(contract, description=''):
#     """
#     Register a contract and make it
#     :param contract:
#     :param description:
#     :return:
#     """
#     global contract_registry
# 
#     if contract.__class__.__name__ in contract_registry:
#         raise ValueError('A contract with the same name already registered')
#     else:
#         contract_registry[contract.__class__.__name__] = contract
# 
#     db_contract = Contract()
#     db_contract.name = contract.__class__.__name__
#     db_contract.created = datetime.datetime.now()
#     db_contract.description = description
# 
#     first_status = Status()
#     first_status.contract = db_contract
#     first_status.when = datetime.datetime.now()
#     first_status.attributes = status(contract).dump()
#     # Genesis key is the name of the contract
#     first_status.key = contract.__class__.__name__.encode('utf-8')
# 
#     DB.session.add(db_contract)
#     DB.session.add(first_status)
#     DB.session.commit()
# 
# class SimpleContract(BaseContract):
#     """
#     Contract that uses SimpleStatus for serialization.
# 
#     The goal of this class is to make a contact feel just like a Python class.
#     """
#     _status_class = SimpleStatus
# 
# Path: pyledger/server/db.py
# DB = Handler()
# 
# Path: pyledger/server/auth.py
# def create_master(password):
# def create_user(name, password):
# def allow(permission):
#     def decorator(func):
# def method_allow(permission):
#     def decorator(func):


# Path: pyledger/server/ws.py
from autobahn.asyncio.websocket import WebSocketServerProtocol, \
    WebSocketServerFactory
from pyledger.server.handlers import handle_request
from pyledger.server.contract import register_contract, SimpleContract
from pyledger.server.db import DB
from pyledger.server.auth import Permissions, method_allow
import asyncio

#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.



loop = asyncio.get_event_loop()


class Protocol(WebSocketServerProtocol):
    contract = None
    bcast_topic = 36*b'0'

    def onConnect(self, request):
        self.factory.register(self)
        print("Client connecting: {0}".format(request.peer))

    def onOpen(self):
        print("WebSocket connection open.")

    def onMessage(self, payload, isBinary):
        try:
            topic = payload[:36]
            payload = payload[36:]

            response = handle_request(payload)