Commits

Ginés Martínez Sánchez committed 73acaa1 Draft

writing inter-event back ways

  • Participants
  • Parent commits 295818c

Comments (0)

Files changed (2)

File ginsfsm/examples/inter_event/schema.svg

      inkscape:pageopacity="0.0"
      inkscape:pageshadow="2"
      inkscape:zoom="0.8830081"
-     inkscape:cx="-240.51795"
-     inkscape:cy="270.8469"
+     inkscape:cx="272.74448"
+     inkscape:cy="361.4463"
      inkscape:current-layer="layer1"
      inkscape:document-units="px"
      showgrid="false"
          sodipodi:role="line"
          x="768.40326"
          y="554.82635"
-         id="tspan2999">Role: banco, *financiera, *bolsa, *publicidad ↓</tspan><tspan
+         id="tspan2999">Role: banco, *financiera, **bolsa, **publicidad ↓</tspan><tspan
          sodipodi:role="line"
          x="768.40326"
          y="569.82635"

File ginsfsm/router.py

         'destination_role',
         'destination_gobj',
         'origin_gaplic',
+        'origin_role',
         'origin_gobj',
         'kw',
     ]
         'message_type',
         'my_gaplic_name',
         'my_roles',
+        'my_roles_back_way',
     ]
     identity_card_ack_fields = [
         'message_type',
             destination_role=None,
             destination_gobj=None,
             origin_gaplic=None,
+            origin_role=None,
             origin_gobj=None,
             my_gaplic_name=None,
             my_roles=None,
+            my_roles_back_way=None,
             kw=None,
             error_message=None,
             reference=None):
         self.destination_role = destination_role
         self.destination_gobj = destination_gobj
         self.origin_gaplic = origin_gaplic
+        self.origin_role = origin_role
         self.origin_gobj = origin_gobj
         self.my_gaplic_name = my_gaplic_name
         self.my_roles = my_roles
+        self.my_roles_back_way = my_roles_back_way
         if kw:
             self.kw = kw
         else:
         self.identity_ack = False
         self.serial = 0
         self.ws = None
+        self.their_roles = None  # their roles anwered in identity ack (with *)
 
     def incr_serial(self):
         self.serial += 1
         return self.serial
 
     def __str__(self):
-        return "%s %s " % (self.gaplic_name, self.route_ref)
+        return "%s %s" % (self.gaplic_name, self.route_ref)
 
     def __repr__(self):
         return "\nSTATIC ROUTE:\n  gaplic_name: %s\n  roles: %s\n  " \
-            "route_ref: %s\n  connex: %s\n" % (
+            "route_ref: %s\n  connex: %s\n  their_roles: %s\n" % (
                 self.gaplic_name,
                 self.roles,
                 self.route_ref,
                 self.connex_handler.config.destinations,
+                self.their_roles,
             )
 
 
         self.identity_ack = True
         self.serial = 0
         self.ws = None
+        self.their_roles = None  # their roles anwered in identity (with ^)
 
     def incr_serial(self):
         self.serial += 1
         return self.serial
 
     def __str__(self):
-        return "%s %s " % (self.gaplic_name, self.route_ref)
+        return "%s %s" % (self.gaplic_name, self.route_ref)
 
     def __repr__(self):
-        return "\nSTATIC ROUTE:\n  gaplic_name: %s\n  roles: %s\n  " \
-            "route_ref: %s\n  gsock: %r\n" % (
+        return "\DINAMYC ROUTE:\n  gaplic_name: %s\n  roles: %s\n  " \
+            "route_ref: %s\n  gsock: %r\n  their_roles: %r\n" % (
                 self.gaplic_name,
                 self.roles,
                 self.route_ref,
                 self.gsock,
+                self.their_roles,
             )
 
 
         self.route_ref = None
         self.identity_ack = False
 
+    def __str__(self):
+        return "%s" % (self.route_ref)
+
+    def __repr__(self):
+        return "\EMPTY ROUTE:\n  route_ref: %s\n" % (
+            self.route_ref,
+        )
+
 
 class GAplicRegistry(object):
     """ GAplics registry.
         self.my_roles = router.gaplic.roles  # self role
         self.static_routes = {}
         self.dynamic_routes = {}
+        self.broadcasted_roles = []
 
     def add_static_route(self, name, roles, urls, connex_mode=None):
         if not isinstance(urls, (list, tuple)):
             return True
         return False
 
+    def subcontracted_roles(self):
+        """ Roles of static routes are our subcontracted roles
+        """
+        registry = self
+        found_roles = set()
+
+        # search in static routes
+        static_routes = registry.static_routes
+        for route_ref in static_routes:
+            route = static_routes[route_ref]
+            for ro in route.roles:
+                found_roles.add(ro)
+
+        found_roles = list(found_roles)
+        return tuple(map(lambda x: '*' + x, found_roles))
+
+    def get_roles_back_way(self):
+        registry = self
+        found_roles = set()
+
+        # search in dynamic routes
+        dynamic_routes = registry.dynamic_routes
+        for route_ref in dynamic_routes:
+            route = dynamic_routes[route_ref]
+            if route.gsock.is_disconnected():
+                continue
+            roles = route.roles
+            for ro in roles:
+                found_roles.add(ro)
+        found_roles = list(found_roles)
+        return tuple(map(lambda x: '^' + x, found_roles))
+
+    def check_broadcast_roles_back_way(self, roles):
+        broadcasted_roles = self.broadcasted_roles
+        to_broadcast = []
+
+        pure_roles = list(
+            map(lambda x: x.lstrip('^'), roles)
+        )
+
+        for idx, ro in enumerate(pure_roles):
+            if ro in self.my_roles:
+                continue  # avoid loops
+            if not ro in broadcasted_roles:
+                to_broadcast.append('^' + roles[idx])
+                broadcasted_roles.append(ro)
+
+        if to_broadcast:
+            self.broadcast_role_back_way(to_broadcast)
+
+    def broadcast_role_back_way(self, roles_back_way):
+        registry = self
+
+        print("BROADCAST BACK WAY ========> %r" % roles_back_way)
+        # search in static routes
+        static_routes = registry.static_routes
+        for route_ref in static_routes:
+            route = static_routes[route_ref]
+            if route.connex_handler.is_disconnected():
+                continue
+            self.router.send_identity_card(route, roles_back_way)
+
+    def role_level(self, role):
+        role = role.strip()
+        level = 0
+        for level, char in enumerate(role):
+            if not role[level] in ('^', '*'):
+                break
+        return level, role[level:]
+
 
 class RouterConnection(SockJSConnection):
     """ Websocket application to work with Pyramid router.
     if not route:
         return -1
     if self.config.trace_router:
-        self.logger.info("%s: new STATIC route: %r" % (
+        self.logger.info("%s: NEW STATIC route: %r" % (
             self.registry.my_gaplic_name,
             route
         ))
 
 def ac_on_open(self, event):
     """
+    By here we receive from both client and server routers
+    that are not pyramid routes.
     """
-    websocket = event.source[-1]
-    websocket.write = websocket.send_jsonfied_message
+    ws = event.source[-1]
+    ws.write = ws.send_jsonfied_message
 
     # send our identity card if iam client
     # we only send the identity card in static routes!
-    if not websocket.config.iam_server:
-        self.send_identity_card(websocket.route)
+    if not ws.config.iam_server:
+        self.send_identity_card(ws.route)
 
 
 def ac_on_close(self, event):
     """
+    By here we receive from both client and server routers
+    that are not pyramid routes.
     """
-    websocket = event.source[-1]
-    route = websocket.route
+    ws = event.source[-1]
+    route = ws.route
     if isinstance(route, DynamicRoute):
         self.registry.delete_route(route.route_ref)
 
 
 def ac_on_message(self, event):
     """
+    By here we receive from both client and server routers
+    that are not pyramid routes.
     """
-    websocket = event.source[-1]
+    ws = event.source[-1]
     msg = event.data
 
     try:
         self,
         'EV_INPUT_MESSAGE',
         msg=msg,
-        websocket=websocket,
+        websocket=ws,
     )
 
 
         gaplic_name = intra_event.my_gaplic_name
         roles = intra_event.my_roles
         this_route = registry.add_dynamic_route(
-            gaplic_name, roles, write, gsock)
+            gaplic_name,
+            roles,
+            write,
+            gsock,
+        )
         if self.config.trace_router:
-            self.logger.info("%s: new DYNAMIC route: %s: %s: %s: %s" % (
+            self.logger.info("%s: NEW DYNAMIC route: %s: %s: %s: %s" % (
                 registry.my_gaplic_name,
                 this_route.route_ref,
                 this_route.gaplic_name,
         ack = IntraEvent(
             message_type='__identity_card_ack__',
             my_gaplic_name=registry.my_gaplic_name,
-            my_roles=registry.my_roles,
+            my_roles=registry.my_roles + registry.subcontracted_roles(),
         )
         if trace_router:
             prefix = '%s ==> %s' % (
                 registry.my_gaplic_name, this_route.route_ref)
             self.trace_intra_event(prefix, ack)
         write(ack.toJSON())
+
+        #
+        #   Broadcast forward the new role's back ways.
+        #
+        registry.check_broadcast_roles_back_way(this_route.roles)
         return
 
     elif message_type == '__identity_card_ack__':
                     intra_event.my_gaplic_name))
                 this_route.gaplic_name = intra_event.my_gaplic_name
 
-        if intra_event.my_roles:
-            for r in intra_event.my_roles:
-                if not r in this_route.roles:
-                    self.logger.info(
+        # check their roles
+        for r in intra_event.my_roles:
+            if not r in this_route.roles:
+                if self.config.update_unknown_roles:
+                    self.logger.warn(
                         "WARNING: updating route %r, adding ROLE %r" % (
                         this_route.route_ref,
                         r))
                     this_route.roles.append(r)
 
+        # check if our subcontracted roles are all
+        for r in this_route.roles:
+            pure_roles = list(
+                map(lambda x: x.lstrip('*'), intra_event.my_roles)
+            )
+            if not r in pure_roles:
+                self.logger.error(
+                    "ERROR: %r LACKS role %r, it has only %r" % (
+                    this_route,
+                    r,
+                    intra_event.my_roles))
+        this_route.their_roles = intra_event.my_roles[:]
+
+        if self.config.trace_router:
+            self.logger.info("%s: UPDATE STATIC route: %r" % (
+                self.registry.my_gaplic_name,
+                this_route
+            ))
+
         registry.fire_pending_events(this_route)
         return
 
         'static routes with format:'
         'name, role1+role2, url1+url2; name2, role2, url2; ...'
     ],
+    'update_unknown_roles': [bool, False, 0, None, "update unknown roles"],
 }
 
 
                 prefix,
             )
             for f in fields:
-                trace += "    %s: %s\n" % (f, getattr(intra_event, f))
+                trace += "    %s: %r\n" % (f, getattr(intra_event, f))
             self.logger.info(trace)
 
         except Exception as e:
                 exc_info=True,
             )
 
-    def send_identity_card(self, route):
+    def send_identity_card(self, route, roles_back_way=None):
         my_gaplic_name = self.registry.my_gaplic_name
         my_roles = self.registry.my_roles
+        if roles_back_way:
+            my_roles_back_way = roles_back_way
+            prefix = '%s ^==> %s' % (my_gaplic_name, route)
+        else:
+            my_roles_back_way = self.registry.get_roles_back_way()
+            prefix = '%s ==> %s' % (my_gaplic_name, route)
 
         idc = IntraEvent(
             message_type='__identity_card__',
             route_ref=None,
             serial=None,
             my_gaplic_name=my_gaplic_name,
-            my_roles=my_roles,
+            my_roles=list(my_roles) + list(my_roles_back_way),
+            #my_roles_back_way=my_roles_back_way,
             kw={},
         )
 
         if self.config.trace_router:
-            prefix = '%s ==> %s' % (my_gaplic_name, route)
             self.trace_intra_event(prefix, idc)
         x = idc.toJSON()
         route.write(x)