get(remotePath, dst, options, addListeners = true) {
    let listeners, rdr, wtr;
    return new Promise((resolve, reject) => {
      if (addListeners) {
        listeners = addTempListeners(this, 'get', reject);
      }
      if (haveConnection(this, 'get', reject)) {
        options = {
          readStreamOptions: { ...options?.readStreamOptions, autoClose: true },
          writeStreamOptions: {
            ...options?.writeStreamOptions,
            autoClose: true,
          },
          pipeOptions: { ...options?.pipeOptions, end: true },
        };
        rdr = this.sftp.createReadStream(remotePath, options.readStreamOptions);
        rdr.once('error', (err) => {
          if (dst && typeof dst === 'string' && wtr && !wtr.destroyed) {
            wtr.destroy();
          }
          reject(this.fmtError(`${err.message} ${remotePath}`, 'get', err.code));
        });
        if (dst === undefined) {
          // no dst specified, return buffer of data
          this.debugMsg('get resolving with buffer of data');
          wtr = concat((buff) => {
            resolve(buff);
          });
        } else if (typeof dst === 'string') {
          // dst local file path
          this.debugMsg(`get called with file path destination ${dst}`);
          const localCheck = haveLocalCreate(dst);
          if (localCheck.status) {
            wtr = fs.createWriteStream(dst, options.writeStreamOptions);
          } else {
            reject(
              this.fmtError(
                `Bad path: ${dst}: ${localCheck.details}`,
                'get',
                localCheck.code,
              ),
            );
          }
        } else {
          this.debugMsg('get called with stream destination');
          wtr = dst;
        }
        wtr.once('error', (err) => {
          reject(
            this.fmtError(
              `${err.message} ${typeof dst === 'string' ? dst : '<stream>'}`,
              'get',
              err.code,
            ),
          );
        });
        rdr.once('end', () => {
          if (typeof dst === 'string') {
            resolve(dst);
          } else if (dst !== undefined) {
            resolve(wtr);
          }
        });
        rdr.pipe(wtr, options.pipeOptions);
      }
    }).finally(() => {
      if (rdr && !rdr.destroyed) {
        rdr.destroy();
      }
      if (addListeners) {
        removeTempListeners(this, listeners, 'get');
      }
    });
  }
get file

If a dst argument is provided, it must be either a string, representing the
local path to where the data will be put, a stream, in which case data is
piped into the stream or undefined, in which case the data is returned as
a Buffer object.

@param {String} remotePath - remote file path
@param {string|stream|undefined} dst - data destination
@param {Object} options - options object with supported properties of readStreamOptions,
                         writeStreamOptions and pipeOptions.
@param {Boolean} addListeners - (Optional) if true, add listeners. Default true

*Important Note*: The ability to set ''autoClose' on read/write streams and 'end' on pipe() calls
is no longer supported. New methods 'createReadStream()' and 'createWriteStream()' have been
added to support low-level access to stream objects.

@return {Promise<String|Stream|Buffer>}