# Copyright (C) 2010-2024 RhodeCode GmbH # # 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 . # # 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.*)') 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