Задать вопрос
Пользователь пока ничего не рассказал о себе

Достижения

Все достижения (3)

Наибольший вклад в теги

Все теги (35)

Лучшие ответы пользователя

Все ответы (27)
  • Yii2: Как вывести input hidden?

    Frostealth
    @Frostealth
    Backend Developer
    <?= $form->field($doctorSearch, "specialization_id")->hiddenInput()->label(false) ?>
    Ответ написан
    Комментировать
  • Ошибка expected expect or finally block.Как решить?

    Frostealth
    @Frostealth
    Backend Developer
    Исключения в python
    try:
        # your code
    except ExceptedException as exc:
        # handle the exception
    Ответ написан
    Комментировать
  • Как объединить две локальные сети через OpenVPN?

    Frostealth
    @Frostealth
    Backend Developer
    Не помешают конфиги OpenVPN и таблицы маршрутизации с обоих роутеров.
    Предполагаю, что на роутере1 (кв1) отсутствует маршрут до сети кв2 через VPN.
    Исходный ответ

    Настройка маршрутов в ASUS описана здесь: https://www.asus.com/ru/support/FAQ/1011706/

    Итак, требуется на роутере1 прописать маршрут к роутеру2 для сети кв2.
    Маршрут примерно такой:
    - IP-адрес сети: 192.168.1.0
    - Сетевая маска: 255.255.255.0
    - Шлюз: IP-адрес роутера2 внутри сети VPN, например 10.8.0.2

    И не забыть прописать для роутера2 статический адрес (10.8.0.2) для OpenVPN. Иначе OpenVPN сервер может выдать роутеру2 другой IP.

    Без маршрута, роутер1 не будет понимать на какой порт/интерфейс направлять запросы к сети 192.168.1.0/24.

    Если не заработает, то, вероятно, через сеть VPN в сеть клиента VPN отсутствует NAT. Тогда следует сконфигурировать брандмауэр (firewall) на роутерах, в т.ч. и на роутере1. Настройка брандмауэра в ASUS описана здесь: https://www.asus.com/ru/support/FAQ/1013630/

    Необходимо, чтобы брандмауэр на роутере1 пропускал запросы из сети 192.168.1.0/24 в сеть 192.268.0.0/24. И наоборот, на роутере2 - из сети 192.168.0.0/24 в сеть 192.168.1.0/24. Без этого роутер будет отбрасывать все запросы во внутреннюю сеть из других сетей.


    При решении данного вопроса с автором возникли проблемы с роутерами ASUS. Клиент (роутер2) ни в какую не видел сеть за сервером (возможно упустил какую-то опцию, "route ..", "iroute" и "push 'route ...'" не помогли). Решение с tap не подходило из-за отключения DHCP на роутере2.
    Основная проблема - это невозможность загрузить в роутер целиком файл конфигурации сервером. А документацию консоли роутера (через ssh) найти быстро не удалось.
    Если кто знает решение, прошу описать его в комментариях.

    Аренда VPS (выделенного сервера) с Ubuntu и поднятие OpenVPN сервера уже на нем с последующим подключением двух роутеров в качестве клиента решили проблему.
    Можно поднять и на ПК в сети, конечно. В таком случае нужно будет добавить статический IP для этого ПК и выполнить проброс портов в настройках роутера.

    Установку и основную настройку сервера OpenVPN помог упростить скрипт https://git.io/vpn, который пришлось редактировать для замены зашитой в нем сети 10.8.0.0 на другую в связи с наличием пересечения данной сети с другой на одном из роутеров.

    Итак, установка и конфигурация сервера OpenVPN на Ubuntu для объединения двух сетей роутеров без выхода в интернет через VPN. Для начала необходимо подключиться к серверу по SSH.

    Установка OpenVPN с помощью скрипта через терминал. Скачиваем скрипт и запускаем его командами ниже.
    >>> wget https://git.io/vpn -O openvpn-install.sh
    >>> sudo bash openvpn-install.sh


    Отвечаем на все запросы скрипта, выбираем протокол UDP.
    После завершения установки открываем файл nano /etc/openvpn/server/server.conf, удаляем все строки, начинающиеся на push, и добавляем следующее:
    ifconfig-pool-persist ipp.txt
    client-config-dir /etc/openvpn/server/ccd
    client-to-client
    
    route 192.168.0.0 255.255.255.0
    push 'route 192.168.0.0 255.255.255.0'
    
    route 192.168.1.0 255.255.255.0
    push 'route 192.168.1.0 255.255.255.0'

    Пояснение к конфигу

    ifconfig-pool-persist ipp.txt - будет сохранять соответствия выданных им IP адресов в файл `ipp.txt`. Таким образом, каждый клиент будет всегда получать один и тот же IP.

    client-config-dir /etc/openvpn/server/ccd - указывает серверу директорию с дополнительной конфигурацией для каждого клиента.

    client-to-client - разрешает передачу данных между клиентами.

    route 192.168.0.0 255.255.255.0 - уведомляет сервер о локальной сети (192.168.0.0/24) клиента.

    push 'route 192.168.0.0 255.255.255.0' - сервер будет передавать маршрут к указанной сети всем клиентам.


    Далее создадим указанную в конфиге директорию sudo mkdir /etc/openvpn/server/ccd.
    И добавим в нее файлы, названия которых будут отражать имена наших клиентов (указываются далее). И пропишем в них какая сеть какому клиенту принадлежит.
    /etc/openvpn/server/ccd/router1

    iroute 192.168.0.0 255.255.255.0

    /etc/openvpn/server/ccd/router2

    iroute 192.168.1.0 255.255.255.0


    Запускаем скрипт снова для добавления клиента. Для добавления второго запускаем потом еще раз.
    После запуска скрипта вводим цифру 1, соответствующую опции 1) Add a new client.
    Здесь же и указываем название клиента (router1, router2).
    >>> sudo bash openvpn-install.sh

    Скачиваем файлы конфигурации для клиентов, которые сгенерировал скрипт, и загружаем соответствующий конфиг при создании OpenVPN клиента на роутерах.
    Маршруты на роутерах прописывать не надо, как и правила в брандмауэре. OpenVPN сервер сам отправляет маршруты клиентам, которые мы указали в его конфиге ранее с помощью push 'route ...'.
    Ответ написан
    1 комментарий
  • Как максимально быстро добавить огромное количество записей в БД без дублей?

    Frostealth
    @Frostealth
    Backend Developer
    Как вариант: отфильтровать `$numbers` на стороне PHP и вставить пачкой.

    // избавляемся от возможных дубликатов
    $numbers = collect($numbers)->unique();
    // pluck('num') вернет нам список значений атрибута num, а не список моделей
    $existingNumbers = Model::query()->whereIn('num', $numbers->toArray())->pluck('num');
    // с помощью diff получаем элементы, которых нет в $existingNumbers
    $newNumbers = $existingNumbers->diff($numbers)->mapWithKeys(function ($value, $key) {
        // ['one', 'two'] => [['num' => 'one'], ['num' => 'two']]
        return [$key => ['num' => $value]];
    });
    
    Model::query()->getConnection()->transaction(function () use ($newNumbers) {
        Model::query()->insert($newNumbers->toArray()); 
    });


    При очень больших данных в БД нужно вытаскивать из БД чанками (пачками определенного размера, например по 500 000), а не сразу все.
    // избавляемся от возможных дубликатов
    $newNumbers = collect($numbers)->unique();
    Model::query()->toBase()->whereIn('num', $numbers->toArray())
          ->chunk(500000, function ($existingNumbers) use (&$newNumbers) {
               // с помощью diff получаем элементы, которых нет в $existingNumbers
              $newNumbers = $newNumbers->diff($existingNumbers);
          });
    
    // ['one', 'two'] => [['num' => 'one'], ['num' => 'two']]
    $newNumbers = $newNumbers->mapWithKeys(function ($value, $key) {
        return [$key => ['num' => $value]];
    });
    
    Model::query()->getConnection()->transaction(function () use ($newNumbers) {
        Model::query()->insert($newNumbers->toArray()); 
    });


    Также можно воспользоваться ON CONFLICT, если СУБД поддерживает подобное. Например, у SQLite - ON CONFLICT DO, у MySQL - INSERT IGNORE. Это позволит избавиться от выгрузки данных из БД, что уменьшит потребление памяти приложением и сократит количество запросов.
    Laravel имеет для этого метод Query::insertOrIgnore(), который будет глушить все ошибки от некоторых БД, но для некоторых не поддерживается. Поддерживаемые БД: MySQL, SQLite, PostreSQL.
    Необходимо, чтобы на атрибут `num` в БД стоял constraint unique, иначе БД просто вставит дубликат.
    $numbers = collect($numbers)->unique()->mapWithKeys(function ($value, $key) {
        return [$key => ['num' => $value]];
    });
    
    Model::query()->getConnection()->transaction(function () use ($numbers) {
        Model::query()->insertOrIgnore($numbers->toArray());
    });


    Индексы и explain изучить не помешает. Размер чанка подобрать по возможностям железа.
    Индекс на num значительно ускорит выборку, но скорость вставки снизится.
    Так же отказ от ORM (Eloquent), объектов и использование голого SQL с PDO ускорит работу.
    На большие данные и нагрузки нужно мощное железо. Может потребоваться масштабирование и т.д.
    Ответ написан
    Комментировать
  • Как не задавать елемент в массиве, если его значение null?

    Frostealth
    @Frostealth
    Backend Developer
    array_filter
    $utms = [
        'utm_source' => $_POST['utm_source'] ?? null,
        'utm_medium' => $_POST['utm_medium'] ?? null,
        'utm_campaign' => $_POST['utm_campaign'] ?? null,
        'utm_term' => $_POST['utm_term'] ?? null,
        'utm_content' => $_POST['utm_content'] ?? null,
    ];
    
    // отфильтрует значения по empty
    $utms = array_filter($utms);
    
    // отфильтрует только null
    $utms = array_filter($utms, fn($val) => $vall !== null)
    Ответ написан
    1 комментарий