public static class Checker {
#region Получения и проверка
/// <summary>
/// Получаем первую строчку со списка с удалением
/// Если строчка не пустая - пытаемся найти внутри прокси (протокол, логин, пароль, ip, порт)
/// Если не нашли - пустое значение
/// Если нашли - возвращаем строчку обратно в список
/// Дальше отправляем запрос на google
/// Если результат не пустой - считаем прокси рабочей
/// Иначе - ждём и после чего пытаемся ещё раз пока не достигнем максимального количества проверки одной прокси
/// Если в результате всё таки прокси не рабочая - получаем следующую с списка и действия повторяются
/// Выход с цикла либо когда получили прокси, либо когда достигли лимита
/// В случае ошибок - пустая строка
/// В случае успеха - рабочий прокси
/// </summary>
/// <param name="project">Необходимо для работы со списком</param>
/// <param name="message">Необходимо для вывода уведомления в лог в Зеннопостер</param>
/// <param name="count">Сколько попыток на проверку 1 прокси</param>
/// <param name="sleep">Сколько ждать между запросами в секундах</param>
/// <param name="max_list">Сколько раз проходить целый список в попытках найти живой прокси</param>
/// <param name="listName">Имя списка в котором содержатся прокси</param>
/// <returns>Получаем прокси либо пустую строку</returns>
public static string GetProxy (IZennoPosterProjectModel project, bool message, int count, int sleep, int max_list, string listName){
string proxy = string.Empty;
if(string.IsNullOrEmpty(listName)) {
project.SendWarningToLog("Имя списка не может быть пустым", message);
return proxy; // Имя списка не может быть пустым
}
int count_lines = project.Lists[listName].Count; // Максимальное количество попыток выполнения
int max = count_lines * max_list;
project.SendInfoToLog(string.Format(@"Количество строк в списке: {0} Максимальное количество попыток: {1}", count_lines, max), message);
for(int i = 0; i< max; i++) {
project.SendInfoToLog(string.Format(@"Попытка: {0} Из: {1}", i, max), message);
string line = GetLine (project, message, listName);
project.SendInfoToLog(string.Format(@"Попытка: {0} Из: {1} Взяли строчку: {2}", i, max, line), message);
if(string.IsNullOrEmpty(line)) {
project.SendInfoToLog(string.Format(@"Попытка: {0} Из: {1} Взяли строчку: {2} - пустая - новая попытка", i, max, line), message);
proxy = string.Empty;
continue; // С пустой строчкой нечего делать - пробуем получить ещё раз
}
proxy = CheckLine (project, message, line); // Убеждаемся что в строчке прокси
project.SendInfoToLog(string.Format(@"Попытка: {0} Из: {1} Сформировали прокси: {2}", i, max, proxy), message);
if(string.IsNullOrEmpty(proxy)) {
project.SendInfoToLog(string.Format(@"Попытка: {0} Из: {1} Сформировали прокси: {2} - пустая строка - новая попытка", i, max, proxy), message);
line = string.Empty;
continue; // С пустой строчкой нечего делать - пробуем получить ещё раз
}
string get = GetData (proxy, count, sleep);
project.SendInfoToLog(string.Format(@"Попытка: {0} Из: {1} Прокси: {2} - результат выполнения запроса: {3}", i, max, proxy, get.Length), message);
AddLine (project, message, line, listName); // В любом случае возвращаем строчку назад в список
project.SendInfoToLog(string.Format(@"Попытка: {0} Из: {1} Прокси: {2} - возвращаем строчку в список: {3}", i, max, proxy, line), message);
if(string.IsNullOrEmpty(get)) {
proxy = string.Empty;
project.SendInfoToLog(string.Format(@"Попытка: {0} Из: {1} Прокси: {2} - результат пустой - новая попытка", i, max, proxy), message);
continue; // Прокси не рабочий
}
else {
// Возможно провести дополнительные проверки
project.SendInfoToLog(string.Format(@"Попытка: {0} Из: {1} Прокси: {2} - считаем прокси рабочим - выходим с цикла", i, max, proxy), message);
break;
}
}
project.SendInfoToLog(string.Format(@"Итого Прокси: {0}", proxy), message);
return proxy;
}
#endregion
#region Попытки в цикле получить данные
/// <summary>
/// Отправка запросов в цикле с указанным временным промежутком указанное количество раз
/// @"https://googe.com" - можно поменять на другой сайт
/// </summary>
/// <param name="proxy">Прокси</param>
/// <param name="count">Количество попыток</param>
/// <param name="sleep">Пауза между запросами в секундах</param>
/// <returns>Возвращает либо пустое значение, либо результат (заголовки) </returns>
private static string GetData (string proxy, int count, int sleep){
string url = @"https://googe.com";
string get = string.Empty;
for(int i=0;i<count;i++) {
get = Get(url, proxy);
if(string.IsNullOrEmpty(get)) {
Thread.Sleep(sleep * 1000); // Ждём указанное количество секунд
continue;
}
break; // Если результат не пустой - выходим с цикла
}
return get;
}
#endregion
#region Проверим строчку
/// <summary>
/// Убеждаемся что строчка содержит прокси, либо возвращаем пустую строку
/// На будущее возможно ещё добавить проверку IP и PORT чтобы они были валидными
/// </summary>
/// <param name="project">Нужно для выывода уведомления в лог</param>
/// <param name="message">Выводить ли уведомления в лог Зеннопостера</param>
/// <param name="line">Строчка которая должна содержать прокси</param>
/// <returns>Возвращает либо собранный прокси либо пустое значение</returns>
private static string CheckLine (IZennoPosterProjectModel project, bool message, string line){
string proxy = string.Empty;
string protocol = string.Empty;
string login = string.Empty;
string password = string.Empty;
string ip = string.Empty;
string port = string.Empty;
line = line.Trim(); // Обрезаем пробелы вначале/конце
if(string.IsNullOrEmpty(line)) return proxy; // Если строчка пустая - вернём пустую строку
if(line.Contains("@")) {
#region Имеем дело с прокси с авторизацией
project.SendInfoToLog(string.Format(@"Имеем дело с прокси с авторизацией {0}", line), message);
// Пример: socks5://login:password@ip:port или login:password@ip:port
string[] el = line.Split(new char[]{'@'}, StringSplitOptions.RemoveEmptyEntries).ToArray();
if (el.Length == 2){
project.SendInfoToLog(string.Format(@"Строка с одним знаком @ - корректная"), message);
string left = el[0];
string right = el[1];
string[] leftData = left.Split(new char[]{':'}, StringSplitOptions.RemoveEmptyEntries).ToArray();
if(leftData.Length == 2) { // протокол не указан - значит http
project.SendInfoToLog(string.Format(@"Имеем дело со строкой без протокола - установим HTTP"), message);
protocol = "http";
login = leftData[0];
password = leftData[1];
}
else if(leftData.Length == 3) { // протокол указан
protocol = leftData[0];
project.SendInfoToLog(string.Format(@"Протокол определен: {0}", protocol), message);
login = leftData[1].TrimStart(new char[]{'/'});
password = leftData[2];
}
else {
project.SendInfoToLog(string.Format(@"Формат не определен - {0}", left), message);
protocol = string.Empty;
login = string.Empty;
password = string.Empty;
project.SendWarningToLog(string.Format(@"Не корректный прокси: {0}", line), message);
}
string[] rightData = right.Split(new char[]{':'}, StringSplitOptions.RemoveEmptyEntries).ToArray();
if(rightData.Length == 2) {
project.SendInfoToLog(string.Format(@"Определили IP:PORT"), message);
ip = rightData[0];
port = rightData[1];
}
else {
project.SendInfoToLog(string.Format(@"IP:PORT не определен"), message);
ip = string.Empty;
port = string.Empty;
}
}
else {
project.SendInfoToLog(string.Format(@"Строка содержит на один знак @ - не верный формат прокси (либо в логине, пароле содержится этот знак)"), message);
protocol = string.Empty;
login = string.Empty;
password = string.Empty;
ip = string.Empty;
port = string.Empty;
project.SendWarningToLog(string.Format(@"Не корректный прокси: {0}", line), message);
}
#endregion
}
else {
#region Имеем дело с прокси без авторизации
project.SendInfoToLog(string.Format(@"Имеем дело с прокси без авторизации {0}", line), message);
// Пример socks5://ip:port ip:port
string[] allData = line.Split(new char[]{':'}, StringSplitOptions.RemoveEmptyEntries).ToArray();
if(allData.Length == 2) { // ip:port
project.SendInfoToLog(string.Format(@"Протокола нет - присвоим HTTP"), message);
protocol = "http";
ip = allData[0];
port= allData[1];
}
else if (allData.Length == 3){ // socks5://ip:port
protocol = allData[0];
project.SendInfoToLog(string.Format(@"Протокол есть - берем {0}",protocol), message);
ip = allData[1].TrimStart(new char[]{'/'});
port = allData[2];
}
else {
project.SendInfoToLog(string.Format(@"Не верный формат {0}",line), message);
protocol = string.Empty;
ip = string.Empty;
port = string.Empty;
}
#endregion
}
if(string.IsNullOrEmpty(protocol)) {
project.SendInfoToLog(string.Format(@"Протокол не сформирован - не верный формат. {0}",line), message);
return proxy; // Если до этого времени протокол не определен - значит возвращаем пустую строку
}
if(!string.IsNullOrEmpty(login) && !string.IsNullOrEmpty(password)) proxy = string.Format(@"{0}://{1}:{2}@{3}:{4}", protocol, login,password, ip,port);
else proxy = string.Format(@"{0}://{1}:{2}", protocol, ip,port);
project.SendInfoToLog(string.Format(@"Сформирован прокси: {0}",proxy), message);
return proxy;
}
#endregion
#region Получение строчки со списка
/// <summary>
/// Получаю первую строчку из списка с удалением
/// В случае любой ошибки - пустая строка + уведомление в лог
/// </summary>
/// <param name="project">Нужно для уведомления в лог</param>
/// <param name="message">Буду ли отображать сообщения в логе Зеннопостера</param>
/// <param name="listName">Имя списка с которого будут браться строчки</param>
/// <returns>Возвращаем либо строчку либо пустое значение</returns>
private static string GetLine (IZennoPosterProjectModel project, bool message, string listName){
string line = string.Empty;
try {
IZennoList list = project.Lists[listName]; // Начинаем работать со списком
lock(SyncObjects.ListSyncer){
List<string> tempList = list.Where( x=> !string.IsNullOrEmpty(x)).ToList();// Взял только не пустые строчки
list.Clear();
if(tempList.Count > 0) list.AddRange(tempList);
int count = list.Count; // Узнаю сколько строчек в списке - перед lock это делать бесполезно
if(count > 0) {
line = list[0].Trim(); // Получил первую строчку и обрезал пробелы вначале/вконце
try {
list.RemoveAt(0); // Удалил первую строчку в списке
// Может быть ошибка, когда один файл используется несколькими шаблонами
// Или например если мы удалили файл в момент работы шаблона
}
catch {
project.SendWarningToLog(string.Format(@"Не смог удалить строчку в списоке: {0} ", listName), message);
}
// Обратно в список сразу же строчку не возвращаю специально
// Так как если в списке всего 1 строка, а работа будет выполняться в 50 потоков
// То получится, что все потоки подхватят 1 прокси, при этом все будут проверять её на работоспособность
}
else {
project.SendWarningToLog(string.Format(@"В списке: {0} нет строк - верну пустую строку", listName), message);
}
}
}
catch (Exception e){
project.SendWarningToLog(string.Format(@"В проекте нет списка с именем {0} {1}", listName, e.Message), message);
}
project.SendInfoToLog(string.Format(@"Получили строчку: {0} ", line), message);
return line;
}
#endregion
#region Возврат строчки в список
/// <summary>
/// Добавляет не пустую строчку в список
/// </summary>
/// <param name="project">Необходимо для работы со списком</param>
/// <param name="message">Необходимо для вывода удомлений</param>
/// <param name="line">Строчка которую будем добавлять в список</param>
/// <param name="listName">Имя списка в который будем добавлять строку</param>
/// <returns>Ничего не возвращаем</returns>
private static void AddLine (IZennoPosterProjectModel project, bool message, string line, string listName){
try {
IZennoList list = project.Lists[listName]; // Начинаем работать со списком
if(!string.IsNullOrEmpty(line)) {
project.SendInfoToLog(string.Format(@"Возвращаем: {0} в список: {1}", line, listName), message);
lock(SyncObjects.ListSyncer){
list.Add(line); // Добавили строчку обратно в список
}
}
else {
project.SendInfoToLog(string.Format(@"Строчка пустая - нет смысла добавлять в список: {0}", listName), message);
}
}
catch {
project.SendWarningToLog(string.Format(@"В шаблоне нет списка с именем {0}", listName), message);
}
}
#endregion
#region Запрос
/// <summary>
/// Обычный запрос
/// </summary>
/// <param name="url">Куда отправить</param>
/// <param name="proxy">Какой прокси использовать</param>
/// <returns>Вернуть либо заголовки либо пустую строку</returns>
private static string Get (string url, string proxy){
string get = string.Empty;
try {
get = ZennoPoster.HttpGet(url, proxy, "UTF-8", ZennoLab.InterfacesLibrary.Enums.Http.ResponceType.HeaderOnly);
}
catch {
get = string.Empty; // В случае ошибки - пустая строка
}
return get;
}
#endregion
}