svn_txn_utils.py
132 lines
| 3.9 KiB
| text/x-python
|
PythonLexer
r5608 | # Copyright (C) 2010-2024 RhodeCode GmbH | |||
r5459 | # | |||
# This program is free software: you can redistribute it and/or modify | ||||
# it under the terms of the GNU Affero General Public License, version 3 | ||||
# (only), as published by the Free Software Foundation. | ||||
# | ||||
# This program is distributed in the hope that it will be useful, | ||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
# GNU General Public License for more details. | ||||
# | ||||
# You should have received a copy of the GNU Affero General Public License | ||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||
# | ||||
# This program is dual-licensed. If you wish to learn more about the | ||||
# RhodeCode Enterprise Edition, including its added features, Support services, | ||||
# and proprietary license terms, please see https://rhodecode.com/licenses/ | ||||
import logging | ||||
import redis | ||||
from ..lib import rc_cache | ||||
from ..lib.ext_json import json | ||||
log = logging.getLogger(__name__) | ||||
redis_client = None | ||||
class RedisTxnClient: | ||||
def __init__(self, url): | ||||
self.url = url | ||||
self._create_client(url) | ||||
def _create_client(self, url): | ||||
connection_pool = redis.ConnectionPool.from_url(url) | ||||
self.writer_client = redis.StrictRedis( | ||||
connection_pool=connection_pool | ||||
) | ||||
self.reader_client = self.writer_client | ||||
def set(self, key, value, expire=24 * 60000): | ||||
self.writer_client.set(key, value, ex=expire) | ||||
def get(self, key): | ||||
return self.reader_client.get(key) | ||||
def delete(self, key): | ||||
self.writer_client.delete(key) | ||||
def get_redis_client(url=''): | ||||
global redis_client | ||||
if redis_client is not None: | ||||
return redis_client | ||||
if not url: | ||||
from rhodecode import CONFIG | ||||
url = CONFIG['vcs.svn.redis_conn'] | ||||
redis_client = RedisTxnClient(url) | ||||
return redis_client | ||||
def extract_svn_txn_id(data: bytes): | ||||
""" | ||||
Helper method for extraction of svn txn_id from submitted XML data during | ||||
POST operations | ||||
""" | ||||
import re | ||||
from lxml import etree | ||||
try: | ||||
root = etree.fromstring(data) | ||||
pat = re.compile(r'/txn/(?P<txn_id>.*)') | ||||
for el in root: | ||||
if el.tag == '{DAV:}source': | ||||
for sub_el in el: | ||||
if sub_el.tag == '{DAV:}href': | ||||
match = pat.search(sub_el.text) | ||||
if match: | ||||
svn_tx_id = match.groupdict()['txn_id'] | ||||
return svn_tx_id | ||||
except Exception: | ||||
log.exception('Failed to extract txn_id') | ||||
def get_txn_id_data_key(repo_path, svn_txn_id): | ||||
log.debug('svn-txn-id: %s, obtaining data path', svn_txn_id) | ||||
repo_key = rc_cache.utils.compute_key_from_params(repo_path) | ||||
final_key = f'{repo_key}.{svn_txn_id}.svn_txn_id' | ||||
log.debug('computed final key: %s', final_key) | ||||
return final_key | ||||
def store_txn_id_data(repo_path, svn_txn_id, data_dict): | ||||
log.debug('svn-txn-id: %s, storing data', svn_txn_id) | ||||
if not svn_txn_id: | ||||
log.warning('Cannot store txn_id because it is empty') | ||||
return | ||||
redis_conn = get_redis_client() | ||||
store_key = get_txn_id_data_key(repo_path, svn_txn_id) | ||||
store_data = json.dumps(data_dict) | ||||
redis_conn.set(store_key, store_data) | ||||
def get_txn_id_from_store(repo_path, svn_txn_id, rm_on_read=False): | ||||
""" | ||||
Reads txn_id from store and if present returns the data for callback manager | ||||
""" | ||||
log.debug('svn-txn-id: %s, retrieving data', svn_txn_id) | ||||
redis_conn = get_redis_client() | ||||
store_key = get_txn_id_data_key(repo_path, svn_txn_id) | ||||
data = {} | ||||
redis_conn.get(store_key) | ||||
try: | ||||
raw_data = redis_conn.get(store_key) | ||||
data = json.loads(raw_data) | ||||
except Exception: | ||||
log.exception('Failed to get txn_id metadata') | ||||
if rm_on_read: | ||||
log.debug('Cleaning up txn_id at %s', store_key) | ||||
redis_conn.delete(store_key) | ||||
return data | ||||