syncthing sync completed or not #1

Open
shailaja wants to merge 1 commits from shailaja/WaitForSyncthing:sync into main

69
syncthing_sync.py Normal file
View File

@ -0,0 +1,69 @@
import os
import xml.etree.ElementTree as ET
import requests
# Global variables for API access - These variables do not change and are set once when the app starts.
API_URL = os.getenv('SYNCTHING_API_URL', 'http://127.0.0.1:8384')
API_KEY = None
def get_api_key(config_file):
""" Retrieve the API key from the local Syncthing configuration XML file. """

Check here:

def _get_key_from_filesystem(self):

The config file is XML, not JSON.

Check here: https://git.bitmessage.org/Sysdeploy/ansible-modules-syncthing/src/commit/31c955c5b938fe59e47313e59f0b719beada1f45/collection/plugins/module_utils/syncthing_api.py#L27 The config file is XML, not JSON.
try:
tree = ET.parse(config_file)
root = tree.getroot()
return root.find('.//apikey').text
except FileNotFoundError:
raise Exception("Configuration file not found.")
except AttributeError:
raise Exception("API key not found in the configuration file.")
def syncthing_request(url):
""" Generic function for Syncthing API GET requests. """

I think we only need GET.

I think we only need `GET`.
headers = {'X-Api-Key': API_KEY}
response = requests.get(url, headers=headers)
response.raise_for_status()
return response.json()
def check_folder_idle(folder_id):
""" Check if the specified folder is idle. """
status_url = f"{API_URL}/rest/db/status?folder={folder_id}"
status = syncthing_request(status_url)
return status['state'] == 'idle'
def long_poll_events(last_event_id, folder_id):
""" Long poll the events endpoint filtering by the last known event ID and specific events. """
events_url = f"{API_URL}/rest/events?since={last_event_id}&events=StateChanged&timeout=60"
events = syncthing_request(events_url)

One more thing, we can filter the events and then the code looks nicer:

events_url = f"{api_url}/rest/events?since={last_event_id}&events=StateChanged&timeout=60"

and then you don't need to check inside main for event['type'] anymore.

One more thing, we can filter the events and then the code looks nicer: `events_url = f"{api_url}/rest/events?since={last_event_id}&events=StateChanged&timeout=60"` and then you don't need to check inside `main` for `event['type']` anymore.
return [event for event in events if event['data']['folder'] == folder_id]
def main():
global API_KEY
folder_id = os.getenv('SYNCTHING_FOLDER_ID')
config_file = os.getenv('SYNCTHING_CONFIG_FILE')
if not folder_id:
raise ValueError("Folder ID must be provided as an environment variable.")
API_KEY = get_api_key(config_file)
# Start by getting the latest event ID
current_events = syncthing_request(f"{API_URL}/rest/events?limit=1")
last_event_id = current_events[0]['id'] if current_events else 0
# Check initial state

It unnecessarily queries and sleeps. I'd prefer something like this:

is_idle = check_folder_idle()

while not is_idle:
    events = long_poll_events()
    for event in events:
        if event['type'] == 'StateChanged',
            event['data']['folder'] == folder_id:
            is_idle = event['data']['to'] == 'idle'
        if is_idle:
            break

I.e. it's not necessary to query the folder state in a loop, as we have the value in the event already. Long poll has a timeout so there's no need for a separate sleep.

We could also make the api_url and api_key variables global, or a class variable, or a module variable, or a class property, because it doesn't change, it's only set once, when the app starts.

It unnecessarily queries and sleeps. I'd prefer something like this: ``` is_idle = check_folder_idle() while not is_idle: events = long_poll_events() for event in events: if event['type'] == 'StateChanged', event['data']['folder'] == folder_id: is_idle = event['data']['to'] == 'idle' if is_idle: break ``` I.e. it's not necessary to query the folder state in a loop, as we have the value in the event already. Long poll has a timeout so there's no need for a separate sleep. We could also make the `api_url` and `api_key` variables global, or a class variable, or a module variable, or a class property, because it doesn't change, it's only set once, when the app starts.
is_idle = check_folder_idle(folder_id)
while not is_idle:
events = long_poll_events(last_event_id, folder_id)
for event in events:
last_event_id = event['id']
is_idle = event['data']['to'] == 'idle'
if is_idle:
print("Folder transitioned to idle.")
break
if __name__ == '__main__':
main()