#!/usr/bin/env python3

# This Python script can be used as an example to send your data in text, NMEA, or GPX file format
# to Trakkit via SFTP.
#
# Set the TAG and PASSWORD variables as defined in Trakkit:
# Boat → Tag & Email → Tag → Create Tag Password.
#
# Maintain a delay of at least 300 seconds between each upload and a maximum file size of 100 MB
# per transfer to ensure fair use of resources and to avoid being banned by the server for
# excessive usage or suspected attack.
#
# You may freely use, modify, adapt, and distribute this code, in whole or in part, for any purpose.
#
# However, it is provided “as is”, without any warranty of any kind, express or implied, including
# but not limited to the warranties of merchantability, fitness for a particular purpose, and
# non-infringement.
#
# The author or contributors shall not be held liable for any claim, damages, or other liability,
# whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with
# the software or the use or other dealings in the software.
#
# No official support or maintenance is provided.



import os
import sys
import lzma
import paramiko
import string
import random
from datetime import datetime

# === Configuration ===
SFTP_TAG = "XXXXXXXXXXXXX"   # TAG FROM TRAKKIT
SFTP_PASSWORD = "yyyyyyyyy"  # TAG PASSWORD FROM TRAKKIT
SFTP_SERVER = "sftp.trakkit.org"
SFTP_PORT = 38888

# === Helpers ===
def random_string(length=5):
    chars = string.ascii_uppercase + string.digits
    return ''.join(random.choices(chars, k=length))

def compress_to_xz(input_file, output_file):
    try:
        with open(input_file, "rb") as f_in, lzma.open(output_file, "wb", preset=9) as f_out:
            while True:
                chunk = f_in.read(1024 * 1024)  # 1 MB chunks
                if not chunk:
                    break
                f_out.write(chunk)
    except Exception as e:
        raise RuntimeError(f"Compression failed: {e}")

# === Main ===
def main():
    if len(sys.argv) != 2:
        print(f"Usage: {sys.argv[0]} <file_to_upload>")
        sys.exit(1)

    input_file = sys.argv[1]
    if not os.path.isfile(input_file):
        print(f"Error: file '{input_file}' not found")
        sys.exit(1)

    file_size = os.path.getsize(input_file)

    # Nom de sortie compressé (ou juste renommé)
    timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
    rnd = random_string()
    base_name = f"{SFTP_TAG}-{timestamp}-{rnd}.xz"
    local_xz = os.path.abspath(base_name)

    try:
        if file_size > 1024:  # > 1Ko: compresser
            print(f"[+] File size {file_size} bytes > 1KB, compressing {input_file} -> {local_xz}")
            compress_to_xz(input_file, local_xz)
        else:  # sinon juste copier et renommer avec .xz pour pas s'embéter. On s'en fout de l'extension
            print(f"[+] File size {file_size} bytes <= 1KB, no compression. Renaming {input_file} -> {local_xz}")
            with open(input_file, "rb") as f_in, open(local_xz, "wb") as f_out:
                f_out.write(f_in.read())

        print(f"[+] Connecting to {SFTP_SERVER}:{SFTP_PORT}")
        transport = paramiko.Transport((SFTP_SERVER, SFTP_PORT))
        transport.connect(username=SFTP_TAG, password=SFTP_PASSWORD)
        sftp = paramiko.SFTPClient.from_transport(transport)

        remote_part = f"/upload/{base_name}.part"
        remote_final = f"/upload/{base_name}"

        print(f"[+] Uploading {local_xz} -> {remote_part}")
        sftp.put(local_xz, remote_part)

        print(f"[+] Renaming {remote_part} -> {remote_final}")
        sftp.rename(remote_part, remote_final)

        print("[+] Done! Upload OK")

    except paramiko.ssh_exception.AuthenticationException:
        print("❌ Authentication failed: wrong SFTP_TAG or SFTP_PASSWORD")
        sys.exit(2)

    except paramiko.ssh_exception.SSHException as e:
        print(f"❌ SSH error: {e}")
        sys.exit(3)

    except FileNotFoundError as e:
        print(f"❌ File error: {e}")
        sys.exit(4)

    except Exception as e:
        print(f"❌ Unexpected error: {e}")
        sys.exit(99)

    finally:
        try:
            if 'sftp' in locals():
                sftp.close()
            if 'transport' in locals():
                transport.close()
        except:
            pass

        # Supprimer le fichier compressé local
        if os.path.exists(local_xz):
            try:
                os.remove(local_xz)
                print(f"[+] Local file {local_xz} removed")
            except Exception as e:
                print(f"[!] Could not remove local file {local_xz}: {e}")

if __name__ == "__main__":
    main()

