initial import
commit
4faab21b67
@ -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
|
||||
|
@ -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
|
Loading…
Reference in New Issue