feat(config): enhance NPM config update with stream management
- Pass authentication credentials to background threads for NPM updates - Improve regex patterns for accurate location block matching - Add support for creating new location blocks for streams - Return success status from NPM config update operations - Update test script to handle errors and apply changes automatically
This commit is contained in:
parent
a80f1c8d3c
commit
3cb15005e2
60
app.py
60
app.py
@ -273,7 +273,7 @@ def add_account() -> Union[Response, str]:
|
|||||||
cache_key_home = f"view/{session['username']}/home"
|
cache_key_home = f"view/{session['username']}/home"
|
||||||
cache.delete(cache_key_home)
|
cache.delete(cache_key_home)
|
||||||
# Run the NPM config update in a background thread
|
# Run the NPM config update in a background thread
|
||||||
thread = threading.Thread(target=_update_npm_config_in_background)
|
thread = threading.Thread(target=_update_npm_config_in_background, args=(session["auth_credentials"],))
|
||||||
thread.start()
|
thread.start()
|
||||||
return redirect(url_for("user_accounts"))
|
return redirect(url_for("user_accounts"))
|
||||||
elif result is False:
|
elif result is False:
|
||||||
@ -330,7 +330,7 @@ def validate_account() -> Tuple[Response, int]:
|
|||||||
cache_key = f"view/{session['username']}/accounts"
|
cache_key = f"view/{session['username']}/accounts"
|
||||||
cache.delete(cache_key)
|
cache.delete(cache_key)
|
||||||
# Run the NPM config update in a background thread
|
# Run the NPM config update in a background thread
|
||||||
thread = threading.Thread(target=_update_npm_config_in_background)
|
thread = threading.Thread(target=_update_npm_config_in_background, args=(session["auth_credentials"],))
|
||||||
thread.start()
|
thread.start()
|
||||||
return jsonify(response_data), response.status_code
|
return jsonify(response_data), response.status_code
|
||||||
except requests.exceptions.RequestException as e:
|
except requests.exceptions.RequestException as e:
|
||||||
@ -515,32 +515,46 @@ def update_config_with_streams(config, streams):
|
|||||||
# Get all stream names from the database
|
# Get all stream names from the database
|
||||||
db_stream_names = {stream['streamName'] for stream in streams}
|
db_stream_names = {stream['streamName'] for stream in streams}
|
||||||
|
|
||||||
# Find all location blocks in the config
|
# Find all location blocks in the config (more accurate pattern)
|
||||||
location_blocks = re.findall(r'location ~ \^/(\w+)\(\.\*\)\$ \{[^}]+\}', config)
|
location_blocks = re.findall(r'location\s+~\s+\^/(\w+)\(\.\*\)\$\s*\{[^}]*return\s+302\s+([^;]+);[^}]*\}', config)
|
||||||
|
existing_stream_names = {stream_name for stream_name, _ in location_blocks}
|
||||||
|
|
||||||
# Remove location blocks that are not in the database
|
# Remove location blocks that are not in the database
|
||||||
for stream_name in location_blocks:
|
for stream_name in existing_stream_names:
|
||||||
if stream_name not in db_stream_names:
|
if stream_name not in db_stream_names:
|
||||||
print(f"Removing location block for stream: {stream_name}")
|
print(f"Removing location block for stream: {stream_name}")
|
||||||
pattern = re.compile(f'location ~ \\^/{re.escape(stream_name)}\\(\\.\\*\\)\\$ {{[^}}]+}}\\s*', re.DOTALL)
|
pattern = re.compile(f'location\\s+~\\s+\\^/{re.escape(stream_name)}\\(\\.\\*\\)\\$\\s*\\{{[^}}]*return\\s+302\\s+[^;]+;[^}}]*\\}}\\s*', re.DOTALL)
|
||||||
config = pattern.sub('', config)
|
config = pattern.sub('', config)
|
||||||
|
|
||||||
# Update existing stream URLs
|
# Update existing stream URLs and create new ones
|
||||||
for stream in streams:
|
for stream in streams:
|
||||||
stream_name = stream['streamName']
|
stream_name = stream['streamName']
|
||||||
stream_url = stream['streamURL']
|
stream_url = stream['streamURL']
|
||||||
if stream_url: # Ensure there is a URL to update to
|
if stream_url: # Ensure there is a URL to update to
|
||||||
# Use a more specific regex to avoid replacing parts of other URLs
|
# Check if location block already exists for this stream
|
||||||
pattern = re.compile(f'(location ~ \\^/{re.escape(stream_name)}\\(\\.\\*\\)\\$ {{\\s*return 302 )([^;]+)(;\\s*}})')
|
if stream_name in existing_stream_names:
|
||||||
config = pattern.sub(f'\\1{stream_url}/$1$is_args$args\\3', config)
|
# Update existing location block
|
||||||
|
pattern = re.compile(f'(location\\s+~\\s+\\^/{re.escape(stream_name)}\\(\\.\\*\\)\\$\\s*\\{{[^}}]*return\\s+302\\s+)([^;]+)(;[^}}]*\\}})', re.DOTALL)
|
||||||
|
config = pattern.sub(f'\\1{stream_url}/$1$is_args$args\\3', config)
|
||||||
|
else:
|
||||||
|
# Create new location block for this stream
|
||||||
|
new_location_block = f'location ~ ^/{stream_name}(.*)$ {{\n return 302 {stream_url}/$1$is_args$args;\n}}\n'
|
||||||
|
# Add the new block at the end of the config (before the last closing brace)
|
||||||
|
config = config.rstrip() + '\n' + new_location_block
|
||||||
|
print(f"Created new location block for stream: {stream_name}")
|
||||||
|
|
||||||
return config
|
return config
|
||||||
|
|
||||||
def _update_npm_config():
|
def _update_npm_config(credentials=None):
|
||||||
"""Helper function to update the NPM config."""
|
"""Helper function to update the NPM config."""
|
||||||
if not session.get('user_id') or int(session.get('user_id')) != 1:
|
# Use provided credentials or get from session (for backward compatibility)
|
||||||
print("Unauthorized attempt to update NPM config.")
|
if credentials is None:
|
||||||
return
|
# This is for backward compatibility when called from background threads
|
||||||
|
# where session context might not be available
|
||||||
|
if not session.get('user_id') or int(session.get('user_id')) != 1:
|
||||||
|
print("Unauthorized attempt to update NPM config.")
|
||||||
|
return False
|
||||||
|
credentials = session.get("auth_credentials")
|
||||||
|
|
||||||
npm = NginxProxyManager(app.config['NPM_HOST'], app.config['NPM_EMAIL'], app.config['NPM_PASSWORD'])
|
npm = NginxProxyManager(app.config['NPM_HOST'], app.config['NPM_EMAIL'], app.config['NPM_PASSWORD'])
|
||||||
npm.login()
|
npm.login()
|
||||||
@ -549,8 +563,8 @@ def _update_npm_config():
|
|||||||
current_config = host.get('advanced_config', '')
|
current_config = host.get('advanced_config', '')
|
||||||
|
|
||||||
backend_url = f"{app.config['BACKEND_URL']}/get_all_stream_urls"
|
backend_url = f"{app.config['BACKEND_URL']}/get_all_stream_urls"
|
||||||
credentials = base64.b64decode(session["auth_credentials"]).decode()
|
decoded_credentials = base64.b64decode(credentials).decode()
|
||||||
username, password = credentials.split(":", 1)
|
username, password = decoded_credentials.split(":", 1)
|
||||||
auth = requests.auth.HTTPBasicAuth(username, password)
|
auth = requests.auth.HTTPBasicAuth(username, password)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -559,28 +573,30 @@ def _update_npm_config():
|
|||||||
streams = response.json()
|
streams = response.json()
|
||||||
except requests.exceptions.RequestException as e:
|
except requests.exceptions.RequestException as e:
|
||||||
print(f"Failed to fetch streams from backend: {e}")
|
print(f"Failed to fetch streams from backend: {e}")
|
||||||
return
|
return False
|
||||||
|
|
||||||
if streams:
|
if streams:
|
||||||
new_config = update_config_with_streams(current_config, streams)
|
new_config = update_config_with_streams(current_config, streams)
|
||||||
npm.update_proxy_host_config(9, new_config)
|
npm.update_proxy_host_config(9, new_config)
|
||||||
print("NPM config updated successfully.")
|
print("NPM config updated successfully.")
|
||||||
|
return True
|
||||||
else:
|
else:
|
||||||
print("Failed to update NPM config.")
|
print("Failed to update NPM config.")
|
||||||
|
return False
|
||||||
|
|
||||||
def _update_npm_config_in_background():
|
def _update_npm_config_in_background(credentials):
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
_update_npm_config()
|
_update_npm_config(credentials)
|
||||||
|
|
||||||
@app.route('/update_host_9_config', methods=['POST'])
|
@app.route('/update_host_9_config', methods=['POST'])
|
||||||
def update_host_9_config():
|
def update_host_9_config():
|
||||||
if not session.get('user_id') or int(session.get('user_id')) != 1:
|
if not session.get('user_id') or int(session.get('user_id')) != 1:
|
||||||
return jsonify({'error': 'Unauthorized'}), 401
|
return jsonify({'error': 'Unauthorized'}), 401
|
||||||
|
|
||||||
thread = threading.Thread(target=_update_npm_config_in_background)
|
thread = threading.Thread(target=_update_npm_config_in_background, args=(session["auth_credentials"],))
|
||||||
thread.start()
|
thread.start()
|
||||||
|
|
||||||
return jsonify({'message': 'NPM config update started in the background.'}), 202
|
return jsonify({'message': 'NPM config update started in the background. Check logs for status.'}), 202
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -120,45 +120,61 @@ def update_config_with_streams(config, streams):
|
|||||||
# Get all stream names from the database
|
# Get all stream names from the database
|
||||||
db_stream_names = {stream['streamName'] for stream in streams}
|
db_stream_names = {stream['streamName'] for stream in streams}
|
||||||
|
|
||||||
# Find all location blocks in the config
|
# Find all location blocks in the config (more accurate pattern)
|
||||||
location_blocks = re.findall(r'location ~ \^/(\w+)\(\.\*\)\$ \{[^}]+\}', config)
|
location_blocks = re.findall(r'location\s+~\s+\^/(\w+)\(\.\*\)\$\s*\{[^}]*return\s+302\s+([^;]+);[^}]*\}', config)
|
||||||
|
existing_stream_names = {stream_name for stream_name, _ in location_blocks}
|
||||||
|
|
||||||
# Remove location blocks that are not in the database
|
# Remove location blocks that are not in the database
|
||||||
for stream_name in location_blocks:
|
for stream_name in existing_stream_names:
|
||||||
if stream_name not in db_stream_names:
|
if stream_name not in db_stream_names:
|
||||||
print(f"Removing location block for stream: {stream_name}")
|
print(f"Removing location block for stream: {stream_name}")
|
||||||
pattern = re.compile(f'location ~ \\^/{re.escape(stream_name)}\\(\\.\\*\\)\\$ {{[^}}]+}}\\s*', re.DOTALL)
|
pattern = re.compile(f'location\\s+~\\s+\\^/{re.escape(stream_name)}\\(\\.\\*\\)\\$\\s*\\{{[^}}]*return\\s+302\\s+[^;]+;[^}}]*\\}}\\s*', re.DOTALL)
|
||||||
config = pattern.sub('', config)
|
config = pattern.sub('', config)
|
||||||
|
|
||||||
# Update existing stream URLs
|
# Update existing stream URLs and create new ones
|
||||||
for stream in streams:
|
for stream in streams:
|
||||||
stream_name = stream['streamName']
|
stream_name = stream['streamName']
|
||||||
stream_url = stream['streamURL']
|
stream_url = stream['streamURL']
|
||||||
if stream_url: # Ensure there is a URL to update to
|
if stream_url: # Ensure there is a URL to update to
|
||||||
# Use a more specific regex to avoid replacing parts of other URLs
|
# Check if location block already exists for this stream
|
||||||
pattern = re.compile(f'(location ~ \\^/{re.escape(stream_name)}\\(\\.\\*\\)\\$ {{\\s*return 302 )([^;]+)(;\\s*}})')
|
if stream_name in existing_stream_names:
|
||||||
config = pattern.sub(f'\\1{stream_url}/$1$is_args$args\\3', config)
|
# Update existing location block
|
||||||
|
pattern = re.compile(f'(location\\s+~\\s+\\^/{re.escape(stream_name)}\\(\\.\\*\\)\\$\\s*\\{{[^}}]*return\\s+302\\s+)([^;]+)(;[^}}]*\\}})', re.DOTALL)
|
||||||
|
config = pattern.sub(f'\\1{stream_url}/$1$is_args$args\\3', config)
|
||||||
|
else:
|
||||||
|
# Create new location block for this stream
|
||||||
|
new_location_block = f'location ~ ^/{stream_name}(.*)$ {{\n return 302 {stream_url}/$1$is_args$args;\n}}\n'
|
||||||
|
# Add the new block at the end of the config (before the last closing brace)
|
||||||
|
config = config.rstrip() + '\n' + new_location_block
|
||||||
|
print(f"Created new location block for stream: {stream_name}")
|
||||||
|
|
||||||
return config
|
return config
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
npm = NginxProxyManager(app_config.NPM_HOST, app_config.NPM_EMAIL, app_config.NPM_PASSWORD)
|
try:
|
||||||
npm.login()
|
npm = NginxProxyManager(app_config.NPM_HOST, app_config.NPM_EMAIL, app_config.NPM_PASSWORD)
|
||||||
host = npm.get_proxy_host(9)
|
npm.login()
|
||||||
if host:
|
host = npm.get_proxy_host(9)
|
||||||
current_config = host.get('advanced_config', '')
|
if host:
|
||||||
print("Current Config:")
|
current_config = host.get('advanced_config', '')
|
||||||
print(current_config)
|
print("Current Config:")
|
||||||
|
print(current_config)
|
||||||
|
|
||||||
streams = get_streams_from_db(app_config.DBHOST, app_config.DBUSER, app_config.DBPASS, app_config.DATABASE, app_config.DBPORT)
|
streams = get_streams_from_db(app_config.DBHOST, app_config.DBUSER, app_config.DBPASS, app_config.DATABASE, app_config.DBPORT)
|
||||||
if streams:
|
if streams:
|
||||||
new_config = update_config_with_streams(current_config, streams)
|
new_config = update_config_with_streams(current_config, streams)
|
||||||
print("\nNew Config:")
|
print("\nNew Config:")
|
||||||
print(new_config)
|
print(new_config)
|
||||||
|
|
||||||
# Uncomment the following line to apply the changes
|
# Apply the changes
|
||||||
npm.update_proxy_host_config(9, new_config)
|
npm.update_proxy_host_config(9, new_config)
|
||||||
print("\nTo apply the changes, uncomment the last line in the main function.")
|
print("\nChanges applied successfully.")
|
||||||
|
else:
|
||||||
|
print("No streams found in database.")
|
||||||
|
else:
|
||||||
|
print("Failed to get proxy host configuration.")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"An error occurred: {e}")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
Loading…
x
Reference in New Issue
Block a user