def __init__(self, name: str, sygnal: "Sygnal", config: Dict[str, Any]): super().__init__(name, sygnal, config) nonunderstood = self.cfg.keys() - self.UNDERSTOOD_CONFIG_FIELDS if nonunderstood: logger.warning( "The following configuration fields are not understood: %s", nonunderstood, ) self.http_pool = HTTPConnectionPool(reactor=sygnal.reactor) self.max_connections = self.get_config( "max_connections", int, DEFAULT_MAX_CONNECTIONS ) self.connection_semaphore = DeferredSemaphore(self.max_connections) self.http_pool.maxPersistentPerHost = self.max_connections tls_client_options_factory = ClientTLSOptionsFactory() # use the Sygnal global proxy configuration proxy_url = sygnal.config.get("proxy") self.http_agent = ProxyAgent( reactor=sygnal.reactor, pool=self.http_pool, contextFactory=tls_client_options_factory, proxy_url_str=proxy_url, ) self.http_request_factory = HttpRequestFactory() self.allowed_endpoints: Optional[List[Pattern[str]]] = None allowed_endpoints = self.get_config("allowed_endpoints", list) if allowed_endpoints: self.allowed_endpoints = list(map(glob_to_regex, allowed_endpoints)) privkey_filename = self.get_config("vapid_private_key", str) if not privkey_filename: raise PushkinSetupException("'vapid_private_key' not set in config") if not os.path.exists(privkey_filename): raise PushkinSetupException("path in 'vapid_private_key' does not exist") try: self.vapid_private_key = Vapid.from_file(private_key_file=privkey_filename) except VapidException as e: raise PushkinSetupException("invalid 'vapid_private_key' file") from e self.vapid_contact_email = self.get_config("vapid_contact_email", str) if not self.vapid_contact_email: raise PushkinSetupException("'vapid_contact_email' not set in config") self.ttl = self.get_config("ttl", int, DEFAULT_TTL)
def __init__(self, name: str, sygnal: "Sygnal", config: Dict[str, Any]) -> None: super().__init__(name, sygnal, config) nonunderstood = set(self.cfg.keys()).difference( self.UNDERSTOOD_CONFIG_FIELDS) if len(nonunderstood) > 0: logger.warning( "The following configuration fields are not understood: %s", nonunderstood, ) self.http_pool = HTTPConnectionPool(reactor=sygnal.reactor) self.max_connections = self.get_config("max_connections", int, DEFAULT_MAX_CONNECTIONS) self.connection_semaphore = DeferredSemaphore(self.max_connections) self.http_pool.maxPersistentPerHost = self.max_connections tls_client_options_factory = ClientTLSOptionsFactory() # use the Sygnal global proxy configuration proxy_url = sygnal.config.get("proxy") self.http_agent = ProxyAgent( reactor=sygnal.reactor, pool=self.http_pool, contextFactory=tls_client_options_factory, proxy_url_str=proxy_url, ) self.api_key = self.get_config("api_key", str) if not self.api_key: raise PushkinSetupException("No API key set in config") # Use the fcm_options config dictionary as a foundation for the body; # this lets the Sygnal admin choose custom FCM options # (e.g. content_available). self.base_request_body = self.get_config("fcm_options", dict, {}) if not isinstance(self.base_request_body, dict): raise PushkinSetupException( "Config field fcm_options, if set, must be a dictionary of options" )
def get_config( self, key: str, type_: Type[T], default: Optional[T] = None ) -> Optional[T]: if key not in self.cfg: return default if not isinstance(self.cfg[key], type_): raise PushkinSetupException( f"{key} is of incorrect type, please check that the entry for {key} is " f"formatted correctly in the config file. " ) return self.cfg[key]
def __init__(self, name, sygnal, config): super().__init__(name, sygnal, config) nonunderstood = set(self.cfg.keys()).difference( self.UNDERSTOOD_CONFIG_FIELDS) if len(nonunderstood) > 0: logger.warning( "The following configuration fields are not understood: %s", nonunderstood, ) platform = self.get_config("platform") if not platform or platform == "production" or platform == "prod": self.use_sandbox = False elif platform == "sandbox": self.use_sandbox = True else: raise PushkinSetupException(f"Invalid platform: {platform}") certfile = self.get_config("certfile") keyfile = self.get_config("keyfile") if not certfile and not keyfile: raise PushkinSetupException( "You must provide a path to an APNs certificate, or an APNs token." ) if certfile: if not os.path.exists(certfile): raise PushkinSetupException( f"The APNs certificate '{certfile}' does not exist.") else: # keyfile if not os.path.exists(keyfile): raise PushkinSetupException( f"The APNs key file '{keyfile}' does not exist.") if not self.get_config("key_id"): raise PushkinSetupException("You must supply key_id.") if not self.get_config("team_id"): raise PushkinSetupException("You must supply team_id.") if not self.get_config("topic"): raise PushkinSetupException("You must supply topic.") if self.get_config("certfile") is not None: self.apns_client = APNs(client_cert=self.get_config("certfile"), use_sandbox=self.use_sandbox) else: self.apns_client = APNs( key=self.get_config("keyfile"), key_id=self.get_config("key_id"), team_id=self.get_config("team_id"), topic=self.get_config("topic"), use_sandbox=self.use_sandbox, ) # without this, aioapns will retry every second forever. self.apns_client.pool.max_connection_attempts = 3
def __init__(self, name: str, sygnal: "Sygnal", config: Dict[str, Any]) -> None: super().__init__(name, sygnal, config) nonunderstood = set(self.cfg.keys()).difference( self.UNDERSTOOD_CONFIG_FIELDS) if len(nonunderstood) > 0: logger.warning( "The following configuration fields are not understood: %s", nonunderstood, ) platform = self.get_config("platform", str) if not platform or platform == "production" or platform == "prod": self.use_sandbox = False elif platform == "sandbox": self.use_sandbox = True else: raise PushkinSetupException(f"Invalid platform: {platform}") certfile = self.get_config("certfile", str) keyfile = self.get_config("keyfile", str) if not certfile and not keyfile: raise PushkinSetupException( "You must provide a path to an APNs certificate, or an APNs token." ) if certfile: if not os.path.exists(certfile): raise PushkinSetupException( f"The APNs certificate '{certfile}' does not exist.") elif keyfile: # keyfile if not os.path.exists(keyfile): raise PushkinSetupException( f"The APNs key file '{keyfile}' does not exist.") if not self.get_config("key_id", str): raise PushkinSetupException("You must supply key_id.") if not self.get_config("team_id", str): raise PushkinSetupException("You must supply team_id.") if not self.get_config("topic", str): raise PushkinSetupException("You must supply topic.") # use the Sygnal global proxy configuration proxy_url_str = sygnal.config.get("proxy") loop = asyncio.get_event_loop() if proxy_url_str: # this overrides the create_connection method to use a HTTP proxy loop = ProxyingEventLoopWrapper(loop, proxy_url_str) # type: ignore if certfile is not None: # max_connection_attempts is actually the maximum number of # additional connection attempts, so =0 means try once only # (we will retry at a higher level so not worth doing more here) self.apns_client = APNs( client_cert=certfile, use_sandbox=self.use_sandbox, max_connection_attempts=0, loop=loop, ) self._report_certificate_expiration(certfile) else: # max_connection_attempts is actually the maximum number of # additional connection attempts, so =0 means try once only # (we will retry at a higher level so not worth doing more here) self.apns_client = APNs( key=self.get_config("keyfile", str), key_id=self.get_config("key_id", str), team_id=self.get_config("team_id", str), topic=self.get_config("topic", str), use_sandbox=self.use_sandbox, max_connection_attempts=0, loop=loop, ) # without this, aioapns will retry every second forever. self.apns_client.pool.max_connection_attempts = 3