func addTorrent(torrentParams lt.AddTorrentParams, wg *sync.WaitGroup) {
	log.Println("Adding torrent")
	error := lt.NewErrorCode()
	torrentHandle = session.GetHandle().AddTorrent(torrentParams, error)
	if error.Value() != 0 {
		log.Fatalln(error.Message())
	}

	log.Println("Enabling sequential download")
	torrentHandle.SetSequentialDownload(true)

	if config.trackers != "" {
		trackers := strings.Split(config.trackers, ",")
		startTier := 256 - len(trackers)
		for n, tracker := range trackers {
			tracker = strings.TrimSpace(tracker)
			announceEntry := lt.NewAnnounceEntry(tracker)
			announceEntry.SetTier(byte(startTier + n))
			log.Printf("Adding tracker: %s", tracker)
			torrentHandle.AddTracker(announceEntry)
		}
	}

	if config.enableScrape {
		log.Println("Sending scrape request to tracker")
		torrentHandle.ScrapeTracker()
	}

	log.Printf("Downloading torrent: %s", torrentHandle.Status().GetName())
	torrentFS = NewTorrentFS(torrentHandle, config.fileIndex)
	defer wg.Done()
}
func buildTorrentParams(uri string) lt.AddTorrentParams {
	fileUri, err := url.Parse(uri)
	torrentParams := lt.NewAddTorrentParams()
	error := lt.NewErrorCode()
	if err != nil {
		log.Fatal(err)
	}
	if fileUri.Scheme == "file" {
		uriPath := fileUri.Path
		if uriPath != "" && runtime.GOOS == "windows" && os.IsPathSeparator(uriPath[0]) {
			uriPath = uriPath[1:]
		}
		absPath, err := filepath.Abs(uriPath)
		if err != nil {
			log.Fatalf(err.Error())
		}
		log.Printf("Opening local file: %s", absPath)
		if _, err := os.Stat(absPath); err != nil {
			log.Fatalf(err.Error())
		}
		torrentInfo := lt.NewTorrentInfo(absPath, error)
		if error.Value() != 0 {
			log.Fatalln(error.Message())
		}
		torrentParams.SetTorrentInfo(torrentInfo)
	} else {
		log.Printf("Will fetch: %s", uri)
		torrentParams.SetUrl(uri)
	}

	log.Printf("Setting save path: %s", config.downloadPath)
	torrentParams.SetSavePath(config.downloadPath)

	if _, err := os.Stat(config.resumeFile); !os.IsNotExist(err) {
		log.Printf("Loading resume file: %s", config.resumeFile)
		bytes, err := ioutil.ReadFile(config.resumeFile)
		if err != nil {
			log.Println(err)
		} else {
			resumeData := lt.NewStdVectorChar()
			count := 0
			for _, byte := range bytes {
				resumeData.PushBack(byte)
				count++
			}
			torrentParams.SetResumeData(resumeData)
		}
	}

	if config.noSparseFile {
		log.Println("Disabling sparse file support...")
		torrentParams.SetStorageMode(lt.StorageModeAllocate)
	}

	return torrentParams
}
func startSession(wg *sync.WaitGroup) {
	log.Println("Starting session...")

	session = lt.NewSession(
		lt.NewFingerprint("LT", lt.LIBTORRENT_VERSION_MAJOR, lt.LIBTORRENT_VERSION_MINOR, 0, 0),
		int(lt.SessionHandleAddDefaultPlugins),
	)
	alertMask := uint(lt.AlertErrorNotification) | uint(lt.AlertStorageNotification) |
		uint(lt.AlertTrackerNotification) | uint(lt.AlertStatusNotification)
	if config.debugAlerts {
		alertMask |= uint(lt.AlertDebugNotification)
	}
	session.GetHandle().SetAlertMask(alertMask)

	settings := session.GetHandle().Settings()
	//default
	settings.SetRequestTimeout(config.requestTimeout)
	settings.SetPeerConnectTimeout(config.peerConnectTimeout)
	settings.SetAnnounceToAllTrackers(true)
	settings.SetAnnounceToAllTiers(true)
	settings.SetTorrentConnectBoost(config.torrentConnectBoost)
	settings.SetConnectionSpeed(config.connectionSpeed)
	settings.SetMinReconnectTime(config.minReconnectTime)
	settings.SetMaxFailcount(config.maxFailCount)
	settings.SetRecvSocketBufferSize(1024 * 1024)
	settings.SetSendSocketBufferSize(1024 * 1024)
	settings.SetRateLimitIpOverhead(true)
	settings.SetMinAnnounceInterval(60)
	settings.SetTrackerBackoff(0)

	//optimizations from pulsar
	settings.SetStrictEndGameMode(true)
	settings.SetRateLimitIpOverhead(true)
	settings.SetNoAtimeStorage(true)
	settings.SetPrioritizePartialPieces(false)
	settings.SetFreeTorrentHashes(true)
	settings.SetUseParoleMode(true)
	settings.SetMixedModeAlgorithm(int(lt.SessionSettingsPreferTcp))
	settings.SetAnnounceDoubleNat(true)
	settings.SetUpnpIgnoreNonrouters(true)
	settings.SetLockDiskCache(true)
	settings.SetDiskCacheAlgorithm(lt.SessionSettingsLargestContiguous)
	settings.SetSeedChokingAlgorithm(int(lt.SessionSettingsFastestUpload))
	settings.SetLazyBitfields(true)
	settings.SetStopTrackerTimeout(1)
	settings.SetAutoScrapeInterval(1200)   // 20 minutes
	settings.SetAutoScrapeMinInterval(900) // 15 minutes
	settings.SetIgnoreLimitsOnLocalNetwork(true)
	settings.SetRateLimitUtp(true)

	//set
	session.GetHandle().SetSettings(settings)

	err := lt.NewErrorCode()
	rand.Seed(time.Now().UnixNano())
	portLower := config.listenPort
	if config.randomPort {
		portLower = rand.Intn(16374) + 49152
	}
	portUpper := portLower + 10
	session.GetHandle().ListenOn(lt.NewStd_pair_int_int(portLower, portUpper), err)
	if err.Value() != 0 {
		log.Fatalln(err.Message())
	}

	settings = session.GetHandle().Settings()
	if config.userAgent != "" {
		settings.SetUserAgent(config.userAgent)
	}
	if config.connectionsLimit >= 0 {
		settings.SetConnectionsLimit(config.connectionsLimit)
	}
	if config.maxDownloadRate >= 0 {
		settings.SetDownloadRateLimit(config.maxDownloadRate * 1024)
	}
	if config.maxUploadRate >= 0 {
		settings.SetUploadRateLimit(config.maxUploadRate * 1024)
	}
	settings.SetEnableIncomingTcp(config.enableTCP)
	settings.SetEnableOutgoingTcp(config.enableTCP)
	settings.SetEnableIncomingUtp(config.enableUTP)
	settings.SetEnableOutgoingUtp(config.enableUTP)
	session.GetHandle().SetSettings(settings)

	if config.dhtRouters != "" {
		routers := strings.Split(config.dhtRouters, ",")
		for _, router := range routers {
			router = strings.TrimSpace(router)
			if len(router) != 0 {
				var err error
				hostPort := strings.SplitN(router, ":", 2)
				host := strings.TrimSpace(hostPort[0])
				port := 6881
				if len(hostPort) > 1 {
					port, err = strconv.Atoi(strings.TrimSpace(hostPort[1]))
					if err != nil {
						log.Fatalln(err)
					}
				}
				session.GetHandle().AddDhtRouter(lt.NewStd_pair_string_int(host, port))
				log.Printf("Added DHT router: %s:%d", host, port)
			}
		}
	}

	log.Println("Setting encryption settings")
	encryptionSettings := lt.NewPeSettings()
	encryptionSettings.SetOutEncPolicy(byte(lt.LibtorrentPe_settingsEnc_policy(config.encryption)))
	encryptionSettings.SetInEncPolicy(byte(lt.LibtorrentPe_settingsEnc_policy(config.encryption)))
	encryptionSettings.SetAllowedEncLevel(byte(lt.PeSettingsBoth))
	encryptionSettings.SetPreferRc4(true)
	session.GetHandle().SetPeSettings(encryptionSettings)

	defer wg.Done()
}