58 def search_external_bang(self):
60 Check if there is a external bang.
61 If yes, update self.result_container and return True
63 if self.search_query.external_bang:
64 self.result_container.redirect_url = get_bang_url(self.search_query)
66 # This means there was a valid bang and the
67 # rest of the search does not need to be continued
68 if isinstance(self.result_container.redirect_url, str):
79 def _get_requests(self):
83 # max of all selected engine timeout
86 # start search-request for all selected engines
87 for engineref in self.search_query.engineref_list:
88 processor = PROCESSORS[engineref.name]
90 # stop the request now if the engine is suspend
91 if processor.extend_container_if_suspended(self.result_container):
94 # set default request parameters
95 request_params = processor.get_params(self.search_query, engineref.category)
96 if request_params is None:
99 counter_inc('engine', engineref.name, 'search', 'count', 'sent')
101 # append request to list
102 requests.append((engineref.name, self.search_query.query, request_params))
104 # update default_timeout
105 default_timeout = max(default_timeout, processor.engine.timeout)
108 max_request_timeout = settings['outgoing']['max_request_timeout']
109 actual_timeout = default_timeout
110 query_timeout = self.search_query.timeout_limit
112 if max_request_timeout is None and query_timeout is None:
113 # No max, no user query: default_timeout
115 elif max_request_timeout is None and query_timeout is not None:
116 # No max, but user query: From user query except if above default
117 actual_timeout = min(default_timeout, query_timeout)
118 elif max_request_timeout is not None and query_timeout is None:
119 # Max, no user query: Default except if above max
120 actual_timeout = min(default_timeout, max_request_timeout)
121 elif max_request_timeout is not None and query_timeout is not None:
122 # Max & user query: From user query except if above max
123 actual_timeout = min(query_timeout, max_request_timeout)
126 "actual_timeout={0} (default_timeout={1}, ?timeout_limit={2}, max_request_timeout={3})".format(
127 actual_timeout, default_timeout, query_timeout, max_request_timeout
131 return requests, actual_timeout
133 def search_multiple_requests(self, requests):
134 # pylint: disable=protected-access
135 search_id = str(uuid4())
137 for engine_name, query, request_params in requests:
138 _search = copy_current_request_context(PROCESSORS[engine_name].search)
139 th = threading.Thread( # pylint: disable=invalid-name
141 args=(query, request_params, self.result_container, self.start_time, self.actual_timeout),
145 th._engine_name = engine_name
148 for th in threading.enumerate(): # pylint: disable=invalid-name
149 if th.name == search_id:
150 remaining_time = max(0.0, self.actual_timeout - (default_timer() - self.start_time))
151 th.join(remaining_time)
154 self.result_container.add_unresponsive_engine(th._engine_name, 'timeout')
155 PROCESSORS[th._engine_name].logger.error('engine timeout')
157 def search_standard(self):
159 Update self.result_container, self.actual_timeout
161 requests, self.actual_timeout = self._get_requests()
163 # send all search-request
165 self.search_multiple_requests(requests)
167 # return results, suggestions, answers and infoboxes
171 def search(self) -> ResultContainer:
172 self.start_time = default_timer()
173 if not self.search_external_bang():
174 if not self.search_answerers():
175 self.search_standard()
176 return self.result_container