Search code examples
typescriptftp

How can I get a group of XML files from a ftp server in Typescript?


I try to load a group of XML files from a ftp Server by using the ftp node module.

It worked not so I needed. No async/await is implemented. It's bad to integrate in good readable code.

Is there a better way?

my bad code is (it work, but this asynchron staff is confused!):

import Client from 'ftp';
import ReadableStream = NodeJS.ReadableStream;

const c = new Client();

function streamToString(stream: ReadableStream) {
    // lets have a ReadableStream as a stream variable
    const chunks = [];

    for await (const chunk of stream) {
        chunks.push(Buffer.from(chunk));
    }

    return Buffer.concat(chunks).toString("utf-8");
}
const getFile = async () => {
    let fname: string = ""

    c.on('ready', () => {
        c.list(".", async (err, list) => {
            if (err) throw err;
            // console.dir(list);
            for (const fileProp of list) {
                console.log("fileProp: " , './' +fileProp.name)
                fname = fileProp.name

                if(fileProp.name.match(/.*\.xml/)){

                     c.get('./' + fileProp.name,  (err, stream) => {
                        if (err) throw err;
                        console.log("fname: " + fname)
                        const result =  streamToString(stream)

                        console.log("file content:\n" + result)
                        return
                    });
                }
            }

            c.end();
        });
    });
    c.on('error', () => {
        console.log('handle error');
    });

    await c.connect({
        host: "myserver.com",
        user: "myuser",
        password: "mypassword",
        //debug: m => console.log(m)
    })

}

Solution

  • The better way is to use the basic-ftp module. The ftp module is very old and has not implemented the async/await feature.

    So with basic-ftp you can implement a clear straight forward solution - simple and good readable.

    import * as streamBuffers from "stream-buffers"
    import * as ftp from "basic-ftp"
    import {FileInfo} from "basic-ftp";
    
    const testFtp = async () => {
        await baseFtpTest()
        console.log("end testFtp")
    }
    
    const baseFtpTest = async () => {
        const client = new ftp.Client()
        client.ftp.verbose = true
        try {
            await client.access({
                host: "myserver.com",
                user: "myuser",
                password: "mypassword",
                //secure: true
            })
    
            console.log(await client.list())
            let flist: FileInfo[] = await client.list()
    
            for (const fileProp of flist) {
                if(fileProp.name.match(/.*\.xml/)) {
                    console.log("fname: " + fileProp.name)
                    let sbuff: streamBuffers.WritableStreamBuffer = new streamBuffers.WritableStreamBuffer()
                    await client.downloadTo(sbuff, fileProp.name)
                    let content: string | false = sbuff.getContentsAsString()
                    console.log("content:", content)
                }
            }
        }
        catch(err) {
            console.log(err)
        }
        client.close()
    }
    
    debugger
    
    testFtp()