client.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. """
  2. Client module
  3. """
  4. import sys
  5. import logging
  6. import re
  7. import time
  8. from datetime import datetime
  9. import json
  10. import requests
  11. import cfscrape
  12. from webbot.webbot import Browser
  13. # get logger
  14. LOGGER = logging.getLogger(__name__)
  15. LOGGER.setLevel(logging.INFO)
  16. # create file handler
  17. FILE_HANDLER = logging.FileHandler('output.log')
  18. FILE_HANDLER.setLevel(logging.DEBUG)
  19. # create console handler
  20. STREAM_HANDLER = logging.StreamHandler()
  21. STREAM_HANDLER.setLevel(logging.INFO)
  22. # create formatter and add it to the handlers
  23. STREAM_FORMATTER = logging.Formatter('%(name)s - %(levelname)s - %(message)s')
  24. STREAM_HANDLER.setFormatter(STREAM_FORMATTER)
  25. FILE_FORMATTER = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
  26. FILE_HANDLER.setFormatter(FILE_FORMATTER)
  27. # add the handlers to logger
  28. LOGGER.addHandler(STREAM_HANDLER)
  29. LOGGER.addHandler(FILE_HANDLER)
  30. class RRClientException(Exception):
  31. """RR exception"""
  32. def __init__(self, *args, **kwargs):
  33. Exception.__init__(self, *args, **kwargs)
  34. LOGGER.warning('RRClientException')
  35. class SessionExpireException(Exception):
  36. """Raise when session has expired"""
  37. def __init__(self, *args, **kwargs):
  38. Exception.__init__(self, *args, **kwargs)
  39. LOGGER.warning('Session has expired')
  40. class NoLogginException(Exception):
  41. """Raise exception when client isn't logged in"""
  42. def __init__(self, *args, **kwargs):
  43. Exception.__init__(self, *args, **kwargs)
  44. LOGGER.warning('Session has expired')
  45. class NoPHPsessidException(Exception):
  46. """Raise exception when cookie isn't found"""
  47. def __init__(self, *args, **kwargs):
  48. Exception.__init__(self, *args, **kwargs)
  49. LOGGER.warning('No phpsessid found')
  50. def session_handler(func):
  51. """Handle expired sessions"""
  52. def wrapper(*args, **kwargs):
  53. instance = args[0]
  54. return try_run(instance, func, *args, **kwargs)
  55. def try_run(instance, func, *args, **kwargs):
  56. try:
  57. return func(*args, **kwargs)
  58. except (SessionExpireException, ConnectionError, ConnectionResetError):
  59. instance.remove_cookie(instance.username)
  60. instance.login()
  61. return try_run(instance, func, *args, **kwargs)
  62. except NoLogginException:
  63. instance.login()
  64. return try_run(instance, func, *args, **kwargs)
  65. return wrapper
  66. class Client:
  67. """class for RR client"""
  68. resource_id = {
  69. 'oil': 3,
  70. 'ore': 4,
  71. 'uranium': 11,
  72. 'diamond': 15,
  73. 'liquid oxygen': 21,
  74. 'helium-3': 24,
  75. 'antirad': 13,
  76. 'energy drink': 17,
  77. 'spacerockets': 20,
  78. 'tanks': 2,
  79. 'aircrafts': 1,
  80. 'missiles': 14,
  81. 'bombers': 16,
  82. 'battleships': 18,
  83. 'moon tanks': 22,
  84. 'space stations': 23
  85. }
  86. cookie = None
  87. var_c = None
  88. login_method = None
  89. username = None
  90. password = None
  91. session = None
  92. def __init__(self, show_window=False):
  93. self.show_window = show_window
  94. LOGGER.info('Init client, show window %s', self.show_window)
  95. def set_credentials(self, credentials):
  96. """Set the credentials"""
  97. LOGGER.info('Setting "%s" credentials', credentials['username'])
  98. self.login_method = credentials['login_method']
  99. self.username = credentials['username']
  100. self.password = credentials['password']
  101. def login(self):
  102. """Login user if needed"""
  103. cookie = self.get_cookie(self.username)
  104. if cookie is None:
  105. LOGGER.info('Client login "%s" username "%s"', self.login_method, self.username)
  106. if self.login_method not in ["g", "google", "v", "vk", "f", "facebook"]:
  107. raise RRClientException("Not a valid login method.")
  108. auth_text = requests.get("https://rivalregions.com").text
  109. web = Browser(showWindow=self.show_window)
  110. method_dict = {
  111. 'g': self.login_google,
  112. 'google': self.login_google,
  113. 'v': self.login_vk,
  114. 'vk': self.login_vk,
  115. 'f': self.login_facebook,
  116. 'facebook': self.login_facebook,
  117. }
  118. if self.login_method in method_dict:
  119. web = method_dict[self.login_method](web, auth_text)
  120. else:
  121. LOGGER.info('Invallid loggin method "%s"', self.login_method)
  122. sys.exit()
  123. LOGGER.debug('Get cookie')
  124. phpsessid = web.get_cookie('PHPSESSID')
  125. if phpsessid:
  126. cookie = self.create_cookie(
  127. phpsessid.get('expiry', None),
  128. phpsessid.get('value', None)
  129. )
  130. self.write_cookie(self.username, cookie)
  131. else:
  132. raise NoPHPsessidException()
  133. LOGGER.debug('closing login tab')
  134. web.close_current_tab()
  135. # new to bypass cloudflare
  136. self.session = cfscrape.CloudflareScraper()
  137. # cloudscraper
  138. # self.session = cloudscraper.CloudScraper(
  139. # browser={'browser': 'chrome', 'mobile': False},
  140. # interpreter='nodejs',
  141. # # debug=False
  142. # debug=True
  143. # )
  144. # old
  145. # self.session = requests.Session()
  146. # self.session.headers.update({'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64)' \
  147. # 'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36'})
  148. self.cookie = cookie
  149. self.session.cookies.set(**cookie)
  150. LOGGER.debug('set the var_c')
  151. response = self.session.get('https://rivalregions.com/#overview')
  152. lines = response.text.split("\n")
  153. for line in lines:
  154. if re.match("(.*)var c_html(.*)", line):
  155. var_c = line.split("'")[-2]
  156. LOGGER.debug('var_c: %s', var_c)
  157. self.var_c = line.split("'")[-2]
  158. def login_google(self, web, auth_text):
  159. """login using Google"""
  160. LOGGER.info('Login method Google')
  161. auth_text1 = auth_text.split('\t<a href="')
  162. auth_text2 = auth_text1[1].split('" class="sa')
  163. web.go_to(auth_text2[0])
  164. LOGGER.info('Typing in username')
  165. web.type(self.username, into='Email')
  166. web.click('Volgende')
  167. time.sleep(2)
  168. LOGGER.info('Typing in password')
  169. web.type(self.password, css_selector="input")
  170. web.click('Inloggen')
  171. web.click(css_selector=".sa_sn.float_left.imp.gogo")
  172. time.sleep(1)
  173. return web
  174. def login_vk(self, web, auth_text):
  175. """login using VK"""
  176. LOGGER.info('Login method VK')
  177. auth_text1 = auth_text.split("(\'.vkvk\').attr(\'url\', \'")
  178. auth_text2 = auth_text1[1].split('&response')
  179. web.go_to(auth_text2[0])
  180. web.type(self.username, into='email')
  181. web.type(self.password, xpath="/html/body/div/div/div/div[2]/form/div/div/input[7]")
  182. web.click('Log in')
  183. return web
  184. def login_facebook(self, web, auth_text):
  185. """login using Facebook"""
  186. LOGGER.info('Login method Facebook')
  187. auth_text1 = auth_text.split('">\r\n\t\t\t\t<div class="sa_sn imp float_left" ')
  188. auth_text2 = auth_text1[0].split('200px;"><a class="sa_link" href="')
  189. url = auth_text2[1]
  190. web.go_to(url)
  191. web.type(self.username, into='Email')
  192. web.type(self.password, into='Password')
  193. web.click('Log In')
  194. time.sleep(5)
  195. web.click(css_selector='.sa_sn.imp.float_left')
  196. return web
  197. @classmethod
  198. def write_cookie(cls, username, cookie):
  199. """Write cookie to file"""
  200. LOGGER.info('Saving cookie for "%s"', username)
  201. cookies = None
  202. try:
  203. with open('cookies.json', 'r') as cookies_file:
  204. cookies = json.load(cookies_file)
  205. except FileNotFoundError:
  206. cookies = {}
  207. cookies[username] = {
  208. 'expires': cookie['expires'],
  209. 'value': cookie['value'],
  210. }
  211. with open('cookies.json', 'w+') as cookies_file:
  212. json.dump(cookies, cookies_file)
  213. LOGGER.info('Saved cookie for "%s"', username)
  214. @classmethod
  215. def get_cookie(cls, username):
  216. """Read cookies for username"""
  217. LOGGER.info('Read cookie for "%s"', username)
  218. try:
  219. with open('cookies.json', 'r') as cookies_file:
  220. cookies = json.load(cookies_file)
  221. for cookie_username, cookie in cookies.items():
  222. if cookie_username == username:
  223. LOGGER.info('Found cookie')
  224. expires = datetime.fromtimestamp(int(cookie['expires']))
  225. if datetime.now() >= expires:
  226. LOGGER.info('Cookie is expired')
  227. return None
  228. cookie = cls.create_cookie(
  229. cookie['expires'],
  230. cookie['value'],
  231. )
  232. return cookie
  233. except FileNotFoundError:
  234. pass
  235. return None
  236. @classmethod
  237. def remove_cookie(cls, username):
  238. """Remove cookie from storage"""
  239. LOGGER.info('Removing cookie for "%s"', username)
  240. cookies = None
  241. try:
  242. with open('cookies.json', 'r') as cookies_file:
  243. cookies = json.load(cookies_file)
  244. except FileNotFoundError:
  245. cookies = {}
  246. cookies.pop(username, None)
  247. with open('cookies.json', 'w+') as cookies_file:
  248. json.dump(cookies, cookies_file)
  249. LOGGER.info('Removed cookie for "%s"', username)
  250. @staticmethod
  251. def create_cookie(expires, value):
  252. """Create cookie"""
  253. return {
  254. 'domain': 'rivalregions.com',
  255. 'name': 'PHPSESSID',
  256. 'path': '/',
  257. 'secure': False,
  258. 'expires': expires,
  259. 'value': value,
  260. }
  261. @session_handler
  262. def get(self, path, add_var_c=False):
  263. """Send get request to Rival Regions"""
  264. if path[0] == '/':
  265. path = path[1:]
  266. params = {}
  267. if add_var_c:
  268. params['c'] = self.var_c
  269. LOGGER.debug('GET: %s var_c: %s', path, add_var_c)
  270. if self.session:
  271. response = self.session.get(
  272. url='https://rivalregions.com/{}'.format(path),
  273. params=params
  274. )
  275. if "Session expired, please, reload the page" in response.text:
  276. raise SessionExpireException()
  277. else:
  278. raise NoLogginException()
  279. return response.text
  280. @session_handler
  281. def post(self, path, data=None):
  282. """Send post request to Rival Regions"""
  283. if path[0] == '/':
  284. path = path[1:]
  285. data['c'] = self.var_c
  286. LOGGER.debug('POST: %s', path)
  287. if self.session:
  288. response = self.session.post(
  289. "https://rivalregions.com/{}".format(path),
  290. data=data
  291. )
  292. if "Session expired, please, reload the page" in response.text:
  293. raise SessionExpireException()
  294. else:
  295. raise NoLogginException()
  296. return response.text
  297. @session_handler
  298. def send_chat(self, language, message):
  299. """send chat message"""
  300. if self.session:
  301. response = self.session.get("https://rivalregions.com/#overview")
  302. if "Session expired, please, reload the page" in response.text:
  303. raise SessionExpireException()
  304. web = Browser(showWindow=self.show_window)
  305. web.go_to('https://rivalregions.com/')
  306. web.add_cookie(self.get_cookie(self.username))
  307. web.go_to('https://rivalregions.com/#slide/chat/lang_{}'.format(language))
  308. web.refresh()
  309. time.sleep(2)
  310. web.type(message, id='message')
  311. web.click(id='chat_send')
  312. web.close_current_tab()
  313. else:
  314. raise NoLogginException()