<s> import logging <EOL> import json <EOL> from dateutil . parser import parse as dateutil_parse <EOL> from uuid import uuid4 <EOL> from nucleus import create_session , notification_signals , PersonaNotFoundError , UnauthorizedError , VesicleStateError , CHANGE_TYPES <EOL> from nucleus . models import Persona , Star , Planet , Starmap , Group , Oneup <EOL> from nucleus . vesicle import Vesicle <EOL> from synapse . electrical import ElectricalSynapse <EOL> from web_ui import app <EOL> ALLOWED_MESSAGE_TYPES = [ <EOL> "<STR_LIT:object>" , <EOL> "<STR_LIT>" , <EOL> ] <EOL> OBJECT_TYPES = ( "<STR_LIT>" , "<STR_LIT>" , "<STR_LIT>" , "<STR_LIT>" , "<STR_LIT>" , "<STR_LIT>" ) <EOL> class Synapse ( ) : <EOL> """<STR_LIT>""" <EOL> _instance = None <EOL> def __new__ ( cls , * args , ** kwargs ) : <EOL> """<STR_LIT>""" <EOL> if not cls . _instance : <EOL> cls . _instance = super ( ElectricalSynapse , cls ) . __new__ ( cls , * args , ** kwargs ) <EOL> return cls . _instance <EOL> def __init__ ( self ) : <EOL> self . logger = logging . getLogger ( '<STR_LIT>' ) <EOL> self . logger . setLevel ( app . config [ '<STR_LIT>' ] ) <EOL> self . starmap = Starmap . query . get ( app . config [ '<STR_LIT>' ] ) <EOL> self . electrical = ElectricalSynapse ( parent = self ) <EOL> self . _connect_signals ( ) <EOL> def _connect_signals ( self ) : <EOL> """<STR_LIT>""" <EOL> signal = notification_signals . signal <EOL> signal ( '<STR_LIT>' ) . connect ( self . on_local_model_change ) <EOL> signal ( '<STR_LIT>' ) . connect ( self . on_new_contact ) <EOL> signal ( '<STR_LIT>' ) . connect ( self . on_request_objects ) <EOL> def _distribute_vesicle ( self , vesicle , recipients = None ) : <EOL> """<STR_LIT>""" <EOL> self . logger . debug ( "<STR_LIT>" . format ( <EOL> vesicle , <EOL> len ( recipients ) if recipients is not None else "<STR_LIT:0>" , <EOL> "<STR_LIT>" if app . config [ "<STR_LIT>" ] else "<STR_LIT>" ) ) <EOL> if not hasattr ( vesicle , "<STR_LIT>" ) : <EOL> raise ValueError ( "<STR_LIT>" ) <EOL> if vesicle . encrypted ( ) : <EOL> keycrypt = json . loads ( vesicle . keycrypt ) <EOL> keycrypt = json . loads ( vesicle . keycrypt ) <EOL> remove_recipients = set ( keycrypt . keys ( ) ) - set ( [ r . id for r in recipients ] ) <EOL> for recipient_id in remove_recipients : <EOL> if recipient_id != vesicle . author_id : <EOL> del keycrypt [ recipient_id ] <EOL> vesicle . keycrypt = json . dumps ( keycrypt ) <EOL> vesicle . add_recipients ( recipients ) <EOL> self . logger . debug ( "<STR_LIT>" . format ( vesicle ) ) <EOL> else : <EOL> vesicle . encrypt ( recipients = recipients ) <EOL> try : <EOL> vesicle . sign ( ) <EOL> except VesicleStateError : <EOL> self . logger . info ( "<STR_LIT>" . format ( vesicle ) ) <EOL> if app . config [ "<STR_LIT>" ] : <EOL> self . electrical . myelin_store ( vesicle ) <EOL> return vesicle <EOL> def _find_source ( self , obj ) : <EOL> """<STR_LIT>""" <EOL> connected_to = lambda p : len ( p . contacts . filter ( Persona . crypt_private != "<STR_LIT>" ) ) > <NUM_LIT:0> <EOL> sources = list ( ) <EOL> if isinstance ( obj , Star ) : <EOL> if connected_to ( obj . author ) : <EOL> sources . append ( obj . author ) <EOL> for starmap in obj . starmaps : <EOL> if connected_to ( starmap . author ) : <EOL> sources . append ( starmap . author ) <EOL> elif isinstance ( obj , Planet ) : <EOL> for star in obj . stars : <EOL> if connected_to ( star . author ) : <EOL> sources . append ( star . author ) <EOL> for starmap in star . starmaps : <EOL> if connected_to ( starmap . author ) : <EOL> sources . append ( starmap . author ) <EOL> elif isinstance ( obj , Starmap ) : <EOL> if connected_to ( obj . author ) : <EOL> sources . append ( obj . author ) <EOL> return sources <EOL> def _log_errors ( self , msg , errors , level = "<STR_LIT:error>" ) : <EOL> """<STR_LIT>""" <EOL> if level not in [ "<STR_LIT>" , "<STR_LIT:info>" , "<STR_LIT>" , "<STR_LIT:error>" ] : <EOL> raise ValueError ( "<STR_LIT>" . format ( level ) ) <EOL> call = getattr ( self . logger , level ) <EOL> call ( "<STR_LIT>" . format ( msg = msg , list = "<STR_LIT>" . join ( str ( e ) for e in errors ) ) ) <EOL> def handle_object ( self , vesicle , reader_persona , session ) : <EOL> """<STR_LIT>""" <EOL> errors = list ( ) <EOL> try : <EOL> action = vesicle . data [ "<STR_LIT:action>" ] <EOL> object_type = vesicle . data [ "<STR_LIT>" ] <EOL> obj = vesicle . data [ "<STR_LIT:object>" ] <EOL> author = vesicle . author <EOL> except KeyError , e : <EOL> errors . append ( "<STR_LIT>" . format ( e ) ) <EOL> if object_type not in OBJECT_TYPES : <EOL> errors . append ( "<STR_LIT>" . format ( object_type ) ) <EOL> if action not in CHANGE_TYPES : <EOL> errors . append ( "<STR_LIT>" . format ( action ) ) <EOL> if errors : <EOL> self . logger . error ( "<STR_LIT>" . format ( "<STR_LIT:\n>" . join ( errors ) ) ) <EOL> else : <EOL> handler = getattr ( self , "<STR_LIT>" . format ( action ) ) <EOL> new_obj = handler ( author , reader_persona , object_type , obj , session ) <EOL> if new_obj is not None : <EOL> vesicle . handled = True <EOL> new_obj . vesicles . append ( vesicle ) <EOL> session . add ( new_obj ) <EOL> session . add ( vesicle ) <EOL> session . commit ( ) <EOL> def handle_object_request ( self , vesicle , reader_persona , session ) : <EOL> """<STR_LIT>""" <EOL> errors = [ ] <EOL> object_id = None <EOL> object_type = None <EOL> try : <EOL> object_id = vesicle . data [ "<STR_LIT>" ] <EOL> object_type = vesicle . data [ "<STR_LIT>" ] <EOL> recipient = vesicle . author <EOL> except KeyError , e : <EOL> errors . append ( "<STR_LIT>" . format ( vesicle , e ) ) <EOL> if object_type not in OBJECT_TYPES : <EOL> errors . append ( "<STR_LIT>" . format ( object_type ) ) <EOL> if errors : <EOL> self . _log_errors ( "<STR_LIT>" , errors ) <EOL> else : <EOL> obj_class = globals ( ) [ object_type ] <EOL> obj = obj_class . query . get ( object_id ) <EOL> if obj is None : <EOL> self . logger . error ( "<STR_LIT>" . format ( <EOL> type = object_type , id = object_id [ : <NUM_LIT:6> ] ) ) <EOL> elif hasattr ( obj , "<STR_LIT>" ) and recipient not in obj . author . contacts : <EOL> self . logger . info ( "<STR_LIT>" . format ( obj , recipient ) ) <EOL> elif isinstance ( obj , Persona ) and recipient not in obj . contacts : <EOL> self . logger . info ( "<STR_LIT>" . format ( obj , recipient ) ) <EOL> else : <EOL> for v in obj . vesicles : <EOL> self . _distribute_vesicle ( v , recipients = [ recipient , ] ) <EOL> self . logger . info ( "<STR_LIT>" . format ( <EOL> obj , len ( obj . vesicles ) , recipient <EOL> ) ) <EOL> vesicle . handled = True <EOL> session . add ( vesicle ) <EOL> session . commit ( ) <EOL> def handle_vesicle ( self , data ) : <EOL> """<STR_LIT>""" <EOL> try : <EOL> vesicle = Vesicle . read ( data ) <EOL> except PersonaNotFoundError , e : <EOL> self . logger . info ( "<STR_LIT>" ) <EOL> resp , errors = self . electrical . persona_info ( e [ <NUM_LIT:0> ] ) <EOL> if errors : <EOL> self . logger . warning ( "<STR_LIT>" . format ( "<STR_LIT:U+002CU+0020>" . join ( errors ) ) ) <EOL> return <EOL> else : <EOL> vesicle = Vesicle . read ( data ) <EOL> if vesicle is None : <EOL> self . logger . error ( "<STR_LIT>" ) <EOL> else : <EOL> old_vesicle = Vesicle . query . get ( vesicle . id ) <EOL> if old_vesicle is not None : <EOL> vesicle = old_vesicle <EOL> session = create_session ( ) <EOL> import keyczar <EOL> if not vesicle . decrypted ( ) : <EOL> try : <EOL> reader_persona = vesicle . decrypt ( ) <EOL> except UnauthorizedError : <EOL> self . logger . info ( "<STR_LIT>" . format ( vesicle ) ) <EOL> except keyczar . errors . InvalidSignatureError : <EOL> self . logger . warning ( "<STR_LIT>" . format ( vesicle , vesicle . id , vesicle . _get_hashcode ( ) ) ) <EOL> return vesicle <EOL> if old_vesicle is None : <EOL> session . add ( vesicle ) <EOL> session . commit ( ) <EOL> if not vesicle . decrypted ( ) : <EOL> self . logger . debug ( "<STR_LIT>" . format ( vesicle ) ) <EOL> else : <EOL> self . logger . info ( "<STR_LIT>" . format ( vesicle , json . dumps ( vesicle . data , indent = <NUM_LIT:2> ) ) ) <EOL> try : <EOL> if vesicle is not None and not vesicle . handled and vesicle . message_type in ALLOWED_MESSAGE_TYPES : <EOL> handler = getattr ( self , "<STR_LIT>" . format ( vesicle . message_type ) ) <EOL> try : <EOL> handler ( vesicle , reader_persona , session ) <EOL> except UnauthorizedError , e : <EOL> self . logger . error ( "<STR_LIT>" . format ( vesicle , e ) ) <EOL> except : <EOL> session . rollback ( ) <EOL> raise <EOL> finally : <EOL> session . flush ( ) <EOL> return vesicle <EOL> def object_insert ( self , author , recipient , object_type , obj , session ) : <EOL> obj_class = globals ( ) [ object_type ] <EOL> missing_keys = obj_class . validate_changeset ( obj ) <EOL> if len ( missing_keys ) > <NUM_LIT:0> : <EOL> raise KeyError ( "<STR_LIT>" . format ( <EOL> "<STR_LIT:U+002CU+0020>" . join ( missing_keys ) , obj_class . __name__ ) ) <EOL> if hasattr ( obj , "<STR_LIT>" ) and author . id != obj [ "<STR_LIT>" ] : <EOL> raise UnauthorizedError ( <EOL> "<STR_LIT>" . format ( <EOL> author , obj [ "<STR_LIT>" ] [ : <NUM_LIT:6> ] ) ) <EOL> o = obj_class . query . get ( obj [ "<STR_LIT:id>" ] ) <EOL> if o is None or ( hasattr ( o , "<STR_LIT>" ) and o . get_state ( ) == - <NUM_LIT:1> ) or ( isinstance ( o , Persona ) and o . _stub is True ) : <EOL> o = obj_class . create_from_changeset ( obj , stub = o , update_sender = author , update_recipient = recipient ) <EOL> session . add ( o ) <EOL> if isinstance ( o , Persona ) : <EOL> o . stub = False <EOL> else : <EOL> o . set_state ( <NUM_LIT:0> ) <EOL> self . logger . info ( "<STR_LIT>" . format ( o ) ) <EOL> return o <EOL> def object_update ( self , author , recipient , object_type , obj , session ) : <EOL> obj_class = globals ( ) [ object_type ] <EOL> missing_keys = obj_class . validate_changeset ( obj , update = True ) <EOL> if len ( missing_keys ) > <NUM_LIT:0> : <EOL> raise KeyError ( "<STR_LIT>" . format ( obj_class . __name__ ) ) <EOL> obj_modified = dateutil_parse ( obj [ "<STR_LIT>" ] ) <EOL> o = obj_class . query . get ( obj [ "<STR_LIT:id>" ] ) <EOL> if o is None : <EOL> self . logger . warning ( "<STR_LIT>" . format ( object_type , obj [ "<STR_LIT:id>" ] [ : <NUM_LIT:6> ] ) ) <EOL> o = obj_class ( id = obj [ "<STR_LIT:id>" ] ) <EOL> o . set_state ( - <NUM_LIT:1> ) <EOL> session . add ( o ) <EOL> self . request_object ( <EOL> object_type = object_type , <EOL> object_id = obj [ "<STR_LIT:id>" ] , <EOL> author = recipient , <EOL> recipient = author , <EOL> session = session ) <EOL> else : <EOL> if o . authorize ( "<STR_LIT>" , author . id ) : <EOL> if o . modified <= obj_modified or ( hasattr ( o , "<STR_LIT>" ) and o . _stub is True ) : <EOL> o . update_from_changeset ( obj , update_sender = author , update_recipient = recipient ) <EOL> if isinstance ( o , Persona ) : <EOL> o . stub = False <EOL> session . add ( o ) <EOL> self . logger . info ( "<STR_LIT>" . format ( o ) ) <EOL> else : <EOL> self . logger . info ( "<STR_LIT>" . format ( obj ) ) <EOL> else : <EOL> self . logger . warning ( "<STR_LIT>" . format ( author , o ) ) <EOL> return o <EOL> def object_delete ( self , author , recipient , object_type , obj , session ) : <EOL> obj_class = globals ( ) [ object_type ] <EOL> for k in [ "<STR_LIT:id>" , "<STR_LIT>" ] : <EOL> if k not in obj . keys ( ) : <EOL> raise KeyError ( "<STR_LIT>" . format ( k , obj_class . __name__ ) ) <EOL> o = obj_class . query . get ( obj [ "<STR_LIT:id>" ] ) <EOL> if o is None : <EOL> self . logger . info ( "<STR_LIT>" . format ( object_type , obj [ "<STR_LIT:id>" ] ) ) <EOL> else : <EOL> if o . authorize ( "<STR_LIT>" , author . id ) : <EOL> if hasattr ( o , "<STR_LIT>" ) : <EOL> o . set_state ( - <NUM_LIT:2> ) <EOL> o . text = None <EOL> session . add ( o ) <EOL> self . logger . info ( "<STR_LIT>" . format ( o ) ) <EOL> else : <EOL> name = str ( o ) <EOL> session . delete ( o ) <EOL> o = None <EOL> self . logger . info ( "<STR_LIT>" . format ( name ) ) <EOL> else : <EOL> self . logger . warning ( "<STR_LIT>" ) <EOL> return o <EOL> def on_new_contact ( self , sender , message ) : <EOL> for k in [ "<STR_LIT>" , "<STR_LIT>" ] : <EOL> if k not in message : <EOL> raise KeyError ( "<STR_LIT>" . format ( k ) ) <EOL> author = Persona . query . get ( message [ "<STR_LIT>" ] ) <EOL> recipient = Persona . query . get ( message [ "<STR_LIT>" ] ) <EOL> session = create_session ( ) <EOL> if recipient . _stub is True : <EOL> self . logger . info ( "<STR_LIT>" . format ( recipient ) ) <EOL> self . request_object ( "<STR_LIT>" , message [ "<STR_LIT>" ] , author , recipient , session ) <EOL> session . commit ( ) <EOL> def on_local_model_change ( self , sender , message ) : <EOL> """<STR_LIT>""" <EOL> CHANGESET_REQUIRED_FIELDS = [ "<STR_LIT>" , "<STR_LIT:action>" , "<STR_LIT>" , "<STR_LIT>" ] <EOL> for k in CHANGESET_REQUIRED_FIELDS : <EOL> if k not in message . keys ( ) : <EOL> raise KeyError ( "<STR_LIT>" . format ( k ) ) <EOL> if message [ "<STR_LIT:action>" ] not in CHANGE_TYPES : <EOL> raise ValueError ( "<STR_LIT>" . format ( message [ "<STR_LIT:action>" ] ) ) <EOL> if message [ "<STR_LIT>" ] not in OBJECT_TYPES : <EOL> raise ValueError ( "<STR_LIT>" . format ( message [ "<STR_LIT>" ] ) ) <EOL> obj_class = globals ( ) [ message [ "<STR_LIT>" ] ] <EOL> obj = obj_class . query . get ( message [ "<STR_LIT>" ] ) <EOL> if obj is None : <EOL> raise Exception ( "<STR_LIT>" . format ( obj_class , message [ "<STR_LIT>" ] ) ) <EOL> author = Persona . query . get ( message [ "<STR_LIT>" ] ) <EOL> data = dict ( { <EOL> "<STR_LIT:action>" : message [ "<STR_LIT:action>" ] , <EOL> "<STR_LIT>" : message [ "<STR_LIT>" ] <EOL> } ) <EOL> if message [ "<STR_LIT:action>" ] == "<STR_LIT>" : <EOL> data [ "<STR_LIT:object>" ] = obj . export ( ) <EOL> elif message [ "<STR_LIT:action>" ] == "<STR_LIT>" : <EOL> data [ "<STR_LIT:object>" ] = obj . export ( update = True ) <EOL> elif message [ "<STR_LIT:action>" ] == "<STR_LIT>" : <EOL> data [ "<STR_LIT:object>" ] = { <EOL> "<STR_LIT:id>" : obj . id , <EOL> "<STR_LIT>" : obj . modified . isoformat ( ) <EOL> } <EOL> if "<STR_LIT>" in message : <EOL> recipients = message [ "<STR_LIT>" ] <EOL> else : <EOL> recipients = author . contacts . all ( ) <EOL> vesicle = Vesicle ( <EOL> id = uuid4 ( ) . hex , <EOL> message_type = "<STR_LIT:object>" , <EOL> data = data , <EOL> author = author , <EOL> handled = True <EOL> ) <EOL> obj . vesicles . append ( vesicle ) <EOL> session = create_session ( ) <EOL> try : <EOL> session . add ( vesicle ) <EOL> session . commit ( ) <EOL> except : <EOL> session . rollback ( ) <EOL> raise <EOL> else : <EOL> self . logger . info ( "<STR_LIT>" . format ( obj , vesicle , vesicle . json ( indent = True ) ) ) <EOL> vesicle = self . _distribute_vesicle ( vesicle , recipients = recipients ) <EOL> session . add ( vesicle ) <EOL> session . commit ( ) <EOL> def on_request_objects ( self , sender , message ) : <EOL> """<STR_LIT>""" <EOL> try : <EOL> object_type = message [ "<STR_LIT:type>" ] <EOL> object_id = message [ "<STR_LIT:id>" ] <EOL> except KeyError , e : <EOL> self . logger . warning ( "<STR_LIT>" . format ( e ) ) <EOL> return <EOL> session = create_session ( ) <EOL> if "<STR_LIT>" in message : <EOL> author = self . electrical . get_persona ( message [ "<STR_LIT>" ] ) <EOL> else : <EOL> author = None <EOL> if "<STR_LIT>" in message : <EOL> recipient = self . electrical . get_persona ( message [ "<STR_LIT>" ] ) <EOL> else : <EOL> recipient = None <EOL> try : <EOL> self . request_object ( object_type , object_id , author , recipient , session ) <EOL> except : <EOL> session . rollback ( ) <EOL> raise <EOL> finally : <EOL> session . flush ( ) <EOL> def request_object ( self , object_type , object_id , author , recipient , session ) : <EOL> """<STR_LIT>""" <EOL> obj_class = globals ( ) [ object_type ] <EOL> obj = obj_class . query . get ( object_id ) <EOL> if recipient is None : <EOL> sources = self . _find_source ( obj ) <EOL> recipient = sources [ <NUM_LIT:0> ] if len ( sources ) > <NUM_LIT:0> else None <EOL> if recipient is None : <EOL> self . logger . error ( "<STR_LIT>" . format ( object_type , object_id [ : <NUM_LIT:6> ] ) ) <EOL> else : <EOL> if author is None : <EOL> author = recipient . contacts . filter_by ( Persona . crypt_private != "<STR_LIT>" ) . first ( ) <EOL> if author is None : <EOL> raise UnauthorizedError ( "<STR_LIT>" ) <EOL> self . logger . info ( "<STR_LIT>" . format ( <EOL> object_type = object_type , object_id = object_id [ : <NUM_LIT:6> ] , author = author , source = recipient ) ) <EOL> data = { <EOL> "<STR_LIT>" : object_type , <EOL> "<STR_LIT>" : object_id <EOL> } <EOL> vesicle = Vesicle ( <EOL> id = uuid4 ( ) . hex , <EOL> message_type = "<STR_LIT>" , <EOL> author = author , <EOL> data = data <EOL> ) <EOL> session . add ( vesicle ) <EOL> session . commit ( ) <EOL> session . refresh ( vesicle ) <EOL> vesicle = self . _distribute_vesicle ( vesicle , recipients = [ recipient ] ) <EOL> session . add ( vesicle ) <EOL> session . commit ( ) <EOL> def shutdown ( self ) : <EOL> self . pool . kill ( ) </s>
