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