

#include <node_api.h>
#include <napi.h>
#include <string>
#include <iostream>
#include <vector>
#include <sstream>
#include <sys/sendfile.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

namespace sendfile_module {
  
Napi::String Save(const Napi::CallbackInfo& info) {
  Napi::Env env = info.Env();
  Napi::String exports = Napi::String::New(env, "");
  return exports;
}

Napi::Number Send(const Napi::CallbackInfo& info) {
  Napi::Env env = info.Env();
  errno = 0;
  unsigned int fd = info[0].As<Napi::Number>();
  unsigned int fdout = info[1].As<Napi::Number>();
  unsigned int sizeint = info[2].As<Napi::Number>();
  // std::basic_string<char> ca = info[3].As<Napi::String>();
  // std::basic_string<char> key = info[4].As<Napi::String>();
  size_t size = sizeint;
  long total_sent = 0;
  long tmp;
  int retries = 0;
  int CHUNK = 1024*2;
  long last_sendfile_response = 0;

  // setsockopt(fdout, SOL_TCP, TCP_ULP, "tls", sizeof("tls"));
  // setsockopt(fdout, IPPROTO_TLS, 0, "tls", sizeof("tls"));

  // struct tls12_crypto_info_aes_gcm_128 crypto_info;

  // crypto_info.info.version = TLS_1_2_VERSION;
  // crypto_info.info.cipher_type = TLS_CIPHER_AES_GCM_128;
  // crypto_info.rec_seq = _rec_seq;
  // crypto_info.key = _key;
  // memcpy(crypto_info.iv, "", TLS_CIPHER_AES_GCM_128_IV_SIZE);
  // memcpy(crypto_info.rec_seq, ca, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE);
  // memcpy(crypto_info.key, key, TLS_CIPHER_AES_GCM_128_KEY_SIZE);
  // memcpy(crypto_info.salt, "", TLS_CIPHER_AES_GCM_128_SALT_SIZE);

  // setsockopt(fdout, SOL_TLS, TLS_TX, &crypto_info, sizeof(crypto_info));

  fd_set fd_out;
  fd_set fd_in;

  while (total_sent < size && retries < 20) {
    FD_ZERO(&fd_out);
    FD_ZERO(&fd_in);
    FD_SET(fdout, &fd_out);
    FD_SET(fd, &fd_in);

    select(fd > fdout ? fd + 1 : fdout + 1, NULL, &fd_out, NULL, NULL);
    // select(fd + 1, NULL, &fd_out, NULL, NULL);
    tmp = total_sent;
    last_sendfile_response = sendfile64(fdout, fd, &tmp, CHUNK);
    if(last_sendfile_response > 0) {
      total_sent += last_sendfile_response;
      errno = 0;
    } else {
      retries++;
    }
  }
  close(fd);
  // close(fdout);
  
  std::cout << "\nSockets closed, error: " << strerror(errno);
  Napi::Number exports = Napi::Number::New(env, total_sent);
  return exports;
}

Napi::Object init(Napi::Env env, Napi::Object exports) {
  exports.Set(Napi::String::New(env, "send"),
              Napi::Function::New(env, Send));
  exports.Set(Napi::String::New(env, "save"),
  Napi::Function::New(env, Save));
    return exports;
  }

  NODE_API_MODULE(send, init);

}