initial import
This commit is contained in:
		
							
								
								
									
										110
									
								
								history_couchdb.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								history_couchdb.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,110 @@ | |||||||
|  | import collections | ||||||
|  | from xonsh.history.base import History | ||||||
|  | import uuid | ||||||
|  | import time | ||||||
|  | import requests | ||||||
|  | import sys | ||||||
|  | import json | ||||||
|  | import threading | ||||||
|  | import queue | ||||||
|  | import random | ||||||
|  |  | ||||||
|  | from requests.auth import HTTPBasicAuth | ||||||
|  |  | ||||||
|  | _auth = HTTPBasicAuth('username', 'password') | ||||||
|  | _url = 'https://couchdbserver.example.com/xonsh-history' | ||||||
|  |  | ||||||
|  | # turn-on the worker thread | ||||||
|  |  | ||||||
|  | class CouchDBHistory(History): | ||||||
|  |     def __init__(self, **kwargs): | ||||||
|  |         super().__init__(**kwargs) | ||||||
|  |         self.gc = None | ||||||
|  |         self.sessionid = self._build_session_id() | ||||||
|  |         self.inps = [] | ||||||
|  |         self.rtns = [] | ||||||
|  |         self.outs = [] | ||||||
|  |         self.tss = [] | ||||||
|  |         self.q = queue.Queue() | ||||||
|  |         threading.Thread(target=self.couch_worker, daemon=True).start() | ||||||
|  |  | ||||||
|  |     def couch_worker(self): | ||||||
|  |         while True: | ||||||
|  |             cmd = self.q.get() | ||||||
|  |             sent = False | ||||||
|  |             delay = 1.0 | ||||||
|  |             while not sent: | ||||||
|  |                 try: | ||||||
|  |                     self._save_to_db(cmd) | ||||||
|  |                     sent = True | ||||||
|  |                 except: | ||||||
|  |                     delay = min(delay*(1+random.random()), 30) | ||||||
|  |                     time.sleep(delay) | ||||||
|  |             self.q.task_done() | ||||||
|  |  | ||||||
|  |     def _build_session_id(self): | ||||||
|  |         ts = int(time.time() * 1000) | ||||||
|  |         return '{}-{}'.format(ts, str(uuid.uuid4())[:18]) | ||||||
|  |  | ||||||
|  |     def append(self, cmd): | ||||||
|  |         self.inps.append(cmd['inp']) | ||||||
|  |         self.rtns.append(cmd['rtn']) | ||||||
|  |         self.outs.append(None) | ||||||
|  |         self.tss.append(cmd.get('ts', (None, None))) | ||||||
|  |         self.q.put(cmd) | ||||||
|  |  | ||||||
|  |     def items(self): | ||||||
|  |         yield from self._get_db_items(self.sessionid) | ||||||
|  |  | ||||||
|  |     def all_items(self, **kwargs): | ||||||
|  |         yield from self._get_db_items() | ||||||
|  |  | ||||||
|  |     def info(self): | ||||||
|  |         data = collections.OrderedDict() | ||||||
|  |         data['backend'] = 'couchdb' | ||||||
|  |         data['sessionid'] = str(self.sessionid) | ||||||
|  |         return data | ||||||
|  |  | ||||||
|  |     def _save_to_db(self, cmd): | ||||||
|  |         data = cmd.copy() | ||||||
|  |         data['inp'] = cmd['inp'].rstrip() | ||||||
|  |         if 'out' in data: | ||||||
|  |             data.pop('out') | ||||||
|  |         data['_id'] = self._build_doc_id() | ||||||
|  |         try: | ||||||
|  |             self._request_db_data('', data=data) | ||||||
|  |         except Exception as e: | ||||||
|  |             msg = 'failed to save history: {}: {}'.format(e.__class__.__name__, e) | ||||||
|  |             print(msg, file=sys.stderr) | ||||||
|  |  | ||||||
|  |     def _get_db_items(self, sessionid=None): | ||||||
|  |         path = '/_all_docs?include_docs=true' | ||||||
|  |         if sessionid is not None: | ||||||
|  |             path += '&start_key="{0}:"&end_key="{0}:z"'.format(sessionid) | ||||||
|  |         try: | ||||||
|  |             r = self._request_db_data(path) | ||||||
|  |         except Exception as e: | ||||||
|  |             msg = 'error when query db: {}: {}'.format(e.__class__.__name__, e) | ||||||
|  |             print(msg, file=sys.stderr) | ||||||
|  |             return | ||||||
|  |         data = json.loads(r.text) | ||||||
|  |         for item in data['rows']: | ||||||
|  |             cmd = item['doc'].copy() | ||||||
|  |             cmd['ts'] = cmd['ts'][0] | ||||||
|  |             yield cmd | ||||||
|  |  | ||||||
|  |     def _build_doc_id(self): | ||||||
|  |         ts = int(time.time() * 1000) | ||||||
|  |         return '{}:{}-{}'.format(self.sessionid, ts, str(uuid.uuid4())[:18]) | ||||||
|  |  | ||||||
|  |     def _request_db_data(self, path, data=None): | ||||||
|  |         global _url, _auth | ||||||
|  |         url = _url + path | ||||||
|  |         headers = {'Content-Type': 'application/json'} | ||||||
|  |         if data is not None: | ||||||
|  |             resp = requests.post(url, json.dumps(data), headers=headers, auth=_auth, timeout=10) | ||||||
|  |         else: | ||||||
|  |             headers = {'Content-Type': 'text/plain'} | ||||||
|  |             resp = requests.get(url, headers=headers, auth=_auth) | ||||||
|  |         return resp | ||||||
|  |  | ||||||
							
								
								
									
										10
									
								
								xonshrc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								xonshrc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | import os.path | ||||||
|  | import sys | ||||||
|  | xonsh_ext_dir = os.path.expanduser('~/.xonsh') | ||||||
|  | if os.path.isdir(xonsh_ext_dir): | ||||||
|  |     sys.path.append(xonsh_ext_dir) | ||||||
|  |  | ||||||
|  | from history_couchdb import CouchDBHistory | ||||||
|  | $XONSH_HISTORY_BACKEND = CouchDBHistory | ||||||
|  |  | ||||||
|  | $PL_RPROMPT = '!' # recommended if you use powerline, as {history} is slow | ||||||
		Reference in New Issue
	
	Block a user