pythonftpqnap

Python watch QNAP FTP directory for changes and send UDP messages


I need to write a program that watches a directory on ftp server and then sends a message with the path to the new file. So I did manage to use watchdog for a local folder with this as I need just the create event:

if __name__ == "__main__":
    patterns = "*"
    ignore_patterns = ""
    ignore_directories = False
    case_sensitive = False
    my_event_handler = PatternMatchingEventHandler(patterns, ignore_patterns, ignore_directories, case_sensitive)

    def on_created(event):
        byte_message = bytes(f"{event.src_path}", "utf-8")
        opened_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        opened_socket.sendto(byte_message, ('address', port))
        print(f"{event.src_path} created")
    
    my_event_handler.on_created = on_created

    path = r"local/path"
    go_recursively = True
    my_observer = Observer()
    my_observer.schedule(my_event_handler, path, recursive=go_recursively)

    my_observer.start()
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        my_observer.stop()

But when I try replacing the path with the folder on that FTP I get Access Denied which is correct as I did't set the login and the password. After that I did this, based on an answer on Stack Overflow:

ftp = FTP()
ftp.set_pasv(True)
ftp.connect("address")
ftp.login('user', 'pass')

def changemon(dir='ftp/path/*'):
    ls_prev = set()

    while True:
        ls = set(ftp.nlst(dir))

        add = ls-ls_prev
        if add: 
            yield add 
        ls_prev = ls
        sleep(5)

for add in changemon():
    byte_message = bytes('\n'.join(r'address%' % i for i in add), 'utf-8')
    opened_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    opened_socket.sendto(byte_message, ('address', port))

The problem with this is that it gets every single file that appears in the dir.

So I need something that I can extract the subfolder names and file names from. Like this: file1 and file2 are newly created:

ftp/path/5000/file1
ftp/path/5001/file2

print('Folder is: ' + foldername)
Folder is: 5000
Folder is: 5001
print('New file is: ' + filename)
New file is: file1
New file is: file2

Any help is welcome.


Solution

  • This is the working solution after me not able to find anything that could help me from the store (and the task was to make it in python):

    from ftplib import FTP
    from time import sleep
    import os
    import byte
    import socket
    import numpy as np
    import pandas as pd
    
    ftp = FTP()
    ftp.set_pasv(True)
    ftp.connect("some-ip-address")
    ftp.login('user', 'password')
    
    def changemon(dir='/dir/*'):
        ls_prev = set()
    
        while True:
            ls = set(ftp.nlst(dir))
    
            add = ls-ls_prev
            if add:
                yield add
    
            ls_prev = ls
            sleep(5)
    
    #tcp
    for add in changemon():
        result = [i for i in add]
        array = np.array(result, dtype='str')
        df = pd.DataFrame(array, columns=None, index=None)
        for a in array:
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.connect((host, port))
            name = a.split('/')
            separator = ''
            path = (r'ip\dir\\' + str(name[2]) + '\\' + str(name[3]))
            device = name[2]
            message = bytes(separator.join(f'{device} desired string for the IP notification  \n'), 'utf-8')
            s.send(message)
            sleep(5)
    

    It's not the prettiest solution, but gets the job done. The slashes are in the oposite direction because the message needs to be read in Windows. The path variable is then inserted in a database.