instances.py 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. ########################################################################
  2. # Searx-Qt - Lightweight desktop application for Searx.
  3. # Copyright (C) 2020-2022 CYBERDEViL
  4. #
  5. # This file is part of Searx-Qt.
  6. #
  7. # Searx-Qt is free software: you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation, either version 3 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # Searx-Qt is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License
  18. # along with this program. If not, see <https://www.gnu.org/licenses/>.
  19. #
  20. ########################################################################
  21. import time
  22. from searxqt.core import log
  23. from searxqt.core.handler import HandlerProto, NetworkTypes
  24. from searxqt.core.instanceVersions import InstanceVersion
  25. from searxqt.core.http import HttpRequest, HttpJsonReponse, ErrorType
  26. from searxqt.core.schema import Schemas
  27. class SearchEngine:
  28. def __init__(self, name, data):
  29. """Model for a search engine data.
  30. @param name: Name of the search engine
  31. @type name: str
  32. @param data: Data of the search engine
  33. @type data: dict
  34. """
  35. self._name = name
  36. self._data = data
  37. def __repr__(self): return self._name
  38. @property
  39. def name(self):
  40. """
  41. @return: returns the name of this search engine.
  42. @rtype: str
  43. """
  44. return self._name
  45. class TLS:
  46. def __init__(self, data):
  47. """Model for a instance it's TLS data.
  48. @param data: dict with the instance it's TLS data.
  49. @type data: dict
  50. """
  51. self._data = data
  52. @property
  53. def data(self): return self._data
  54. @property
  55. def version(self):
  56. """Returns the TLS version used.
  57. @return:
  58. @rtype: str
  59. """
  60. return self.data.get('version', "")
  61. @property
  62. def certificate(self):
  63. """Returns a TLSCertificate object.
  64. @return:
  65. @rtype: TLSCertificate
  66. """
  67. return TLSCertificate(self.data.get('certificate', {}))
  68. class TLSCertificate:
  69. def __init__(self, data):
  70. """Model for a instance it's TLS certificate-data.
  71. @param data: dict with the instance it's TLS certificate-data.
  72. @type data: dict
  73. """
  74. self._data = data
  75. @property
  76. def data(self): return self._data
  77. @property
  78. def version(self):
  79. """
  80. @return:
  81. @rtype: int
  82. """
  83. return self.data.get('version', 0)
  84. @property
  85. def issuer(self):
  86. """
  87. @return:
  88. @rtype: TLSCertificateIssuer
  89. """
  90. return TLSCertificateIssuer(self.data.get('issuer', {}))
  91. class TLSCertificateIssuer:
  92. def __init__(self, data):
  93. """Model for a instance it's TLS certificate-issuer-data.
  94. @param data: dict with the instance it's
  95. TLS certificate-issuer-data.
  96. @type data: dict
  97. """
  98. self._data = data
  99. @property
  100. def data(self): return self._data
  101. @property
  102. def commonName(self):
  103. """
  104. @rtype: str
  105. """
  106. return self.data.get('commonName', "")
  107. @property
  108. def countryName(self):
  109. """
  110. @rtype: str
  111. """
  112. return self.data.get('countryName', "")
  113. @property
  114. def organizationName(self):
  115. """
  116. @rtype: str
  117. """
  118. return self.data.get('organizationName', "")
  119. class Network:
  120. def __init__(self, data):
  121. """Model for a instance it's network data.
  122. @param data: dict with the instance it's network data.
  123. @type data: dict
  124. """
  125. self._data = data
  126. @property
  127. def data(self): return self._data
  128. @property
  129. def ipv6(self):
  130. """
  131. @return: If ipv6 is enabled on this instance.
  132. @rtype: bool
  133. """
  134. return self.data.get('ipv6', False)
  135. @property
  136. def ips(self):
  137. """
  138. @return: A list with NetworkIP objects
  139. @rtype: list
  140. """
  141. return [NetworkIP(ip, data)
  142. for ip, data in self.data.get('ips', {}).items()]
  143. @property
  144. def asnPrivacy(self):
  145. """
  146. @return: -1 no asn privacy, 0 asn privacy, -2 unknown.
  147. @rtype: int
  148. """
  149. return self.data.get('asn_privacy', -2)
  150. class NetworkIP:
  151. def __init__(self, ip, data):
  152. """Model for a network ip data.
  153. @param ip: ip address
  154. @type ip: str
  155. @param data: dict with a network ip data.
  156. @type data: dict
  157. """
  158. self._ip = ip
  159. self._data = data
  160. def __repr__(self):
  161. return (
  162. f"IP: {self.ip} Reverse: {self.reverse} " \
  163. f"FieldType: {self.fieldType} asnCidr: {self.asnCidr}"
  164. )
  165. def __str__(self): return repr(self)
  166. @property
  167. def ip(self):
  168. """
  169. @return: ip address
  170. @rtype: str
  171. """
  172. return self._ip
  173. @property
  174. def data(self): return self._data
  175. @property
  176. def reverse(self):
  177. """
  178. @return:
  179. @rtype: str
  180. """
  181. return self.data.get('reverse', None)
  182. @property
  183. def fieldType(self):
  184. """
  185. @return: Record type
  186. @rtype: str
  187. """
  188. return self.data.get('field_type', None)
  189. @property
  190. def asnCidr(self):
  191. """
  192. @return:
  193. @rtype: str
  194. """
  195. return self.data.get('asn_cidr', None)
  196. @property
  197. def httpsPort(self):
  198. """
  199. @return:
  200. @rtype: bool
  201. """
  202. return self.data.get('https_port', None)
  203. class Instance:
  204. def __init__(self, url, data):
  205. """Model for a SearX instance.
  206. @param url: Url of the instance
  207. @type url: str
  208. @param data: Data of the instance
  209. @type data: dict
  210. """
  211. self._url = url
  212. self._data = data
  213. self._version = InstanceVersion(self._data.get('version', ''))
  214. if not self._version.isValid():
  215. log.debug(f"Invalid version {self._version}: {self._version.error()}", cls=Instance)
  216. def __str__(self): return self.url
  217. def __repr__(self): return str(self)
  218. @property
  219. def data(self): return self._data
  220. @property
  221. def url(self):
  222. """
  223. @return: returns the url of this instance.
  224. @rtype: str
  225. """
  226. return self._url
  227. @property
  228. def main(self):
  229. """Returns False when not set.
  230. @return: ?
  231. @rtype: bool
  232. """
  233. return self._data.get('main', False)
  234. @property
  235. def networkType(self):
  236. """ Network type; see core/handler.py:NetworkTypes
  237. @return: Network protocol used (Web, Tor, I2P from NetworkTypes)
  238. @rtype: int
  239. """
  240. return self._data.get('network_type', 0)
  241. @property
  242. def version(self):
  243. """Returns a empty string when none found.
  244. @return: Returns the instance it's version.
  245. @rtype: InstanceVersion
  246. """
  247. return self._version
  248. @property
  249. def engines(self):
  250. """
  251. Returns a empty string when none found.
  252. @return: Returns a list with SearchEngine objects
  253. @rtype: list
  254. """
  255. return [SearchEngine(name, data) for name, data in self._data.get(
  256. 'engines', {}).items()]
  257. @property
  258. def tls(self):
  259. """
  260. @rtype: TLS
  261. """
  262. return TLS(self._data.get('tls', {}))
  263. @property
  264. def network(self):
  265. """
  266. @rtype: Network
  267. """
  268. return Network(self._data.get('network', {}))
  269. class Stats2Result(HttpJsonReponse):
  270. Schema = Schemas['searx_space_instances']
  271. class Stats2(HandlerProto):
  272. """ This class holds the instances.json data and will be passed
  273. to other classes (Instances, Engines)
  274. """
  275. URL = "https://searx.space/"
  276. def __init__(self, httpThread, httpSettings):
  277. HandlerProto.__init__(self, httpThread, httpSettings)
  278. def updateFinishedCb(self, response):
  279. # FIXME, for now its working because in searx-qt we reimplement it.
  280. pass
  281. def _updateFinished(self, response):
  282. if response.error != ErrorType.Success:
  283. self.updateFinishedCb(response)
  284. return
  285. self.setData(response.json())
  286. self._lastUpdated = time.time()
  287. # Processing (use our own definition of network types
  288. for url, data in self.instances.items():
  289. data.update({"network_type": NetworkTypes.netTypeFromUrl(url)})
  290. self.updateFinishedCb(response)
  291. def updateInstances(self):
  292. """Fetches instances.json from a searx-stats2 instance.
  293. """
  294. url = Stats2.URL.rstrip('/') + '/data/instances.json'
  295. request = HttpRequest(url,
  296. self.httpSettings.newRequestSettings())
  297. response = Stats2Result(request, self._updateFinished)
  298. self._httpThread.get(response)