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