• Технический нейминг серверов. По какому принципу называть сервера?

    Vamp
    @Vamp
    Я использую нейминг по физическому расположению сервера.

    {имя дц}-{номер стойки}-{номер юнита в стойке}

    Получается что-то типа:

    miran-8-40
    itsoft-1-1

    Если хотите покороче и фикс длину, можно брать первую букву ДЦ (или две буквы, если есть совпадения) и выравнивать цифры ведущим нулём:

    m-08-40
    i-01-01

    Если серверов не так много чтобы арендовать стойки целиком, то просто порядковый номер сервера:

    m-01
    i-15

    Ну или два/три ведущих нуля, если количество серверов 1000/10000:

    m-001
    i-015

    Самый короткий вариант нейминга у меня получился 2х символьный.

    Почему не 1 символ?
    Ответ написан
    3 комментария
  • Платформа/движок для сбора обращений граждан?

    Vamp
    @Vamp
    Подойдёт любая тикетница. Например, OTRS или osTicket. Каждое обращение - новый тикет. Тикетам можно настраивать напоминания, если они не закрыты какое-то время (sla), приоритеты.
    Ответ написан
    Комментировать
  • Как в терминале открыть путь до папки?

    Vamp
    @Vamp
    Выполнить один раз на сервере команду:
    echo 'cd /papka' >> ~/.bashrc
    Ответ написан
    Комментировать
  • Как правильно написать свой обработчик ошибок php?

    Vamp
    @Vamp
    Как правило, обычные ошибки не обрабатывают в таком обработчике, а конвертируют в ErrorException.

    function error_handler(
        $error_code,
        $error_message,
        $error_file_name,
        $error_line
        // $error_context - не объявляйте error_context,
        // он объявлен deprecated в PHP 7.2, а в 8.0 уже удалён
      ){
    
        throw new ErrorException($error_message, 0, $error_code, $error_file_name, $error_line);
    
      }
    
      set_error_handler('error_handler', -1);

    Ну а дальше ловите исключения как обычно.

    // some code...
    
    $host_db = '127.0.0.1';
    $login_db = 'root';
    $password_db = '';
    $database_db = 'some_db';
    
    $DB = new PDO('mysql:host=' . $host_db . ';dbname=' . $database_db, $login_db, $password_db);
    $DB -> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    try {
        $DB -> beginTransaction();
    
        // some code...
    
        $DB -> commit();
    } catch (\Throwable $e) {
        $DB->rollback();
    }
    // some code...
    Ответ написан
    6 комментариев
  • Как происходит связывание с предыдущим узлом в LinkedStack?

    Vamp
    @Vamp
    1. Просто чтобы продемонстрировать использование паттерна sentinel value. В данном конкретном примере можно было обойтись просто null.

    2. В присваивании сначала выполняется правая часть - создаётся объект Node, которому в аргументы конструктора передается item и текущее значение, хранящееся в переменной top. После этого переменной top присваивается ссылка на этот новый объект.

    Это более короткий вариант следующего кода:
    Node<T> oldTop = top;
    top = new Node<T>(item, oldTop);
    Ответ написан
    4 комментария
  • Какие из бекенд фреймворков наиболее "самодостаточные"?

    Vamp
    @Vamp
    Ответ написан
    Комментировать
  • ООП: Правильно ли архитектурно так делать?

    Vamp
    @Vamp
    Возможно, это нормально, так и должно быть ? или как архитектурно правильно решать подобное?

    Это нормально. Безликие массивы становятся осмысленными сущностями. Такой код становится проще понимать и поддерживать.

    Используемый вами подход называется data transfer object (DTO). Широко распространенная практика. DTO отлично сочетается с иммутабельностью, которая присутствует в ваших классах.

    Единственная претензия только к тотальному отсутствию комментариев. Неплохо было бы описать классы и каждый параметр на предмет что он означает, зачем нужен и где его можно использовать.

    В результате, на каком-то уровне приложения, происходит выборка, а дальше создаются все необходимые объекты, и внедряются друг в друга. (кстати, как называется этот слой приложения, и в чьей зоне ответственности эта задача ?)

    Называется ORM. Находится в ответственности ORM слоя/фреймворка.
    Ответ написан
    4 комментария
  • Как настроить xdebug для докера на vps?

    Vamp
    @Vamp
    У вас сложности с тем, что xdebug является инициатором коннекта на ваш домашний ip. И если домашний провайдер выдаёт вам не белый IP, то напрямую такой коннект сделать не удастся.

    Выходом может быть проброс порта через ssh.

    ssh -R 9003:172.17.0.2:9003 user@vpsaddr
    Данная команда установит ssh соединение с логином user на ваш vps по адресу vpsaddr и откроет на этом сервере порт 9003, который сквозь ssh соединение будет прозрачно проксироваться на 9003 порт уже на вашем локальном компьютере.

    Вам нужно будет только узнать какой локальный IP адрес у вашего контейнера и подставить его вместо 172.17.0.2, который я указал для примера.

    Узнать его можно командой
    docker inspect ваш-контейнер | grep IPAddress
    Этот ip адрес нужно прописать в xdebug.client_host и в опцию -R вместо 172.17.0.2.
    Ответ написан
    8 комментариев
  • Что за фигурные скобки в Java?

    Vamp
    @Vamp
    Эта конструкция называется блоком статической инициализации. Есть ещё точно такой же блок динамической инициализации, только без ключевого слова static.

    Блоки инициализации нужны для задания начальных значений полям класса.
    class Initable2 {
        static int staticNonFinal;
    
        public static void main(String[] args) {
            System.out.println(staticNonFinal);
        }
    }

    Данный пример выведет ноль, хотя переменной staticNonFinal не присваивалось никакое значение. Java гарантирует, что любые поля класса будут проинициализированы "нулевым" значением. То есть компилятор неявно вставляет в класс блок статической инициализации, в котором переменной staticNonFinal присваивается ноль.

    class Initable2 {
        static int staticNonFinal;
    
        // Вот этот блок будет добавлен к
        // вашему классу во время компиляции.
        static {
            staticNonFinal = 0;
        }
    
        public static void main(String[] args) {
            System.out.println(staticNonFinal);
        }
    }


    Разумеется, вы можете инициализировать переменные своими значениями:
    class Initable2 {
        static int staticNonFinal = 42;
    
        static String a = "hello";
    
        static Cache<String, Integer> b = CacheBuilder.newBuilder()
            .maximumSize(100)
            .expireAfterWrite(10, TimeUnit.MINUTES)
            .build();
    }

    И тогда компилятор в блоке инициализации будет подставлять ваши значения вместо нулей:
    class Initable2 {
        static int staticNonFinal;
    
        static String a;
    
        static Cache<String, Integer> b;
    
        static {
            staticNonFinal = 42;
            a = "hello";
            b = CacheBuilder.newBuilder()
                .maximumSize(100)
                .expireAfterWrite(10, TimeUnit.MINUTES)
                .build();
        }
    }

    А если вашей переменной требуется какая-то сложная инициализация, которую одной строкой не представить (как в примере с Cache), то тогда вам придется написать блок инициализации явным образом вручную:
    class Initable2 {
        static int staticNonFinal = 42;
    
        static Map<Integer, String> statusCodes = new HashMap<>();
    
        static {
            statusCodes.put(200, "OK");
            statusCodes.put(404, "Not Found");
            statusCodes.put(418, "I'm a teapot");
        }
    }

    И тогда компилятор сгенерирует вам такой код:
    class Initable2 {
        static int staticNonFinal;
    
        static Map<Integer, String> statusCodes;
    
        static {
            staticNonFinal = 42;
            statusCodes = new HashMap<>()
            statusCodes.put(200, "OK");
            statusCodes.put(404, "Not Found");
            statusCodes.put(418, "I'm a teapot");
        }
    }


    Точно таким же способом инициализируются и нестатические поля при помощи блока динамической инициализации (перед таким блоком отсутствует ключевое слово static и выглядит как просто фигурные скобки в теле класса). Каждый раз при создании объекта класса сначала выполняется блок динамической инициализации, а затем конструктор. Именно в таком порядке. Блок статической инициализации выполняется один раз при загрузке класса в память.

    Блоки динамической инициализации редко используются программистами, так как проще всего сделать "инициализацию" в конструкторе (в кавычках, потому что формальная инициализация уже была выполнена перед запуском конструктора и конструктор просто переписывает уже инициализированное значение своим, поэтому более точным термином здесь будет переприсваивание). Но блоки статической инициализации используются довольно часто, так как статических конструкторов не существует.

    Вот эти все блоки инициализации были придуманы создателями языка java чтобы исключить целый класс лютых ошибок, связанных с доступом к неинициализированным переменным, характерный для языков си и си++.
    Ответ написан
    Комментировать
  • Как сделать свою mvn dependency?

    Vamp
    @Vamp
    Для этого нужно создать maven project. В pom.xml этого проекта прописать group, artifact и version. Затем собрать проект командой mvn install

    Maven скомпилирует код вашего проекта, упакует в jar и скопирует этот jar вместе с pom.xml в ваш локальный maven репозиторий.

    Далее в другом проекте подключаете свою зависимость как любую другую зависимость, указывая group, artifact и version, которые прописали ранее.
    Ответ написан
    Комментировать
  • Как мониторить работу скрипта PHP?

    Vamp
    @Vamp
    Начните с настройки директив slowlog в конфиге fpm.

    request_slowlog_timeout mixed
    The timeout for serving a single request after which a PHP backtrace will be dumped to the 'slowlog' file. A value of '0' means 'Off'. Available units: s(econds)(default), m(inutes), h(ours), or d(ays). Default value: 0.

    slowlog string
    The log file for slow requests. Default value: #INSTALL_PREFIX#/log/php-fpm.log.slow.

    Как только какой-либо скрипт работает дольше request_slowlog_timeout, снимается стек трейс данного скрипта и записывается в текстовый файл по пути, указанному в slowlog. Если тормозит какое-то конкретное место, то в стек трейсе будет видно какое. Например, если тормозит база, то в slow логе в топе стек трейса будет, например, вызов PDOStatement::execute.
    Ответ написан
    Комментировать
  • Всегда ли выполняется выполняется блок finally?

    Vamp
    @Vamp
    Автор правильно пишет. Если исключение выбросится на строке lnputFile in = new InputFile("Cleanup.java")j, то оно попадёт сразу в catch(Exception e) { System.out.println("Ошибка при конструировании InputFile"); }. Здесь finally не выполняется, так как исполнение кода не заходит в try блок, к которому прикреплён тот finally.

    Но если исключение стрельнет где-то внутри цикла while((s = in.getLine()) != null), то сработает внутренний catch блок и finally блок. Внешний catch не будет выполнен.

    А если в блоке try либо catch выполнить System.exit() ?

    В таком случае finally блок не будет выполнен, так как javadoc System.exit() чётко пишет: "This method never returns normally." А раз метод не возвращает управление, то try блок не выполняется до конца, соответственно finally не запускается.
    Ответ написан
    Комментировать
  • Когда использовать Collection, а когда Iterator?

    Vamp
    @Vamp
    В каких случаях следует идти через Collection, а в каких через Iterator? (особенно если надо просто пробежаться всем элементам).

    Зависит от объекта, по которому вы хотите просто пробежаться. Если он имплементирует интерфейс Iterable (или унаследованный от него Collection), то for(Pet p:pets) - ваш вариант.

    Через Iterator следует идти, если вы хотите пробежаться по элементам и в процессе пробежки удалить какие-то элементы из итерируемой коллекции. Сделать это безопасно можно только через Iterator.

    Решение с Iterator выглядит привлекательно при написании класса, в котором реали­зация интерфейса Collection затруднена или непрактична.

    Здесь автор имеет ввиду, если вы сами пишете класс, по которому можно "пробежаться". В этом случае проще всего сделать это через итератор, так как в нем меньше методов, которые необходимо реализовать, по сравнению с интерфейсом Collection.
    Ответ написан
    Комментировать
  • Почему так работают битовые сдвиги в Java?

    Vamp
    @Vamp
    Битовый сдвиг для типа long не может превышать 63. Поэтому сдвиг 1L << 64 будет преобразован jvm в 1L << (64 & 0x3f), в результате чего получается 1L << 0 и поэтому у вас значение не изменяется.

    Вашу задачу решает сдвиг 1L << 63. Единица изначально находится на 1 позиции (позиции нумеруются справа налево) и сдвигается влево на 63 позиции. Вы получаете желаемую единицу на 64 позиции с 63 нулями позади.

    Что касается 128L << 56, то здесь всё корректно и логично. Единица находится на 8 позции и имеет 7 нулей сзади. Сдвигая её на 56 позиций, у вас получается желаемый результат - единица на 64 позиции (8 + 56) и 63 нуля позади (7 нулей + 56).
    Ответ написан
    Комментировать
  • Каковы шансы сгенерировать одинаковые onion домены?

    Vamp
    @Vamp
    И по какому принципу они вообще генерируются(v3)?

    Генерируется ключевая пара размером 256 бит по алгоритму ed25519. Публичный ключ затем кодируется в base32 вместе с некоторыми служебными данными - номером версии (3) и контрольной суммой. Получившаяся строка и является доменом в зоне onion.

    Если делать полный перебор (а других вариантов я не вижу), то нужно сгенерировать до 2256 ключевых пар. Если взять миллиард компьютеров, которые будут одновременно и без пересечений друг с другом генерировать ключевую пару каждую наносекунду, то все пары можно перебрать примерно за 36*1041 млрд лет, что кажется мне достаточно малым шансом, учитывая, что возраст вселенной всего чуть менее 14 млрд лет.

    Надо отметить, что не все варианты из 256-битового пространства удовлетворяют ed25519. Но даже если отбросить 99% вариантов как невалидные и не тратить время на их генерацию, то перебор оставшихся 1% все равно будет невообразимо дольше возраста вселенной.
    Ответ написан
    Комментировать
  • Почему не работает dependency NametagEdit?

    Vamp
    @Vamp
    Вероятнее всего неправильно указан repository

    Попробуйте вместо
    <repository>
        <id>upstream</id>
        <url>https://ci.nametagedit.com/plugin/repository/everything/com/nametagedit/nametagedit/</url>
    </repository>


    прописать это
    <repository>
        <id>upstream</id>
        <url>https://ci.nametagedit.com/plugin/repository/everything/</url>
    </repository>
    Ответ написан
    4 комментария
  • Получения энтропии для генератора случайных чисел в PHP - как можно сделать случайность по настоящему случайной?

    Vamp
    @Vamp
    Если вам не нужна криптографическая стойкость, то заморочки с генератором истинно случайных чисел абсолютно неоправданы. ГСЧ на вихре мерсенна отлично подходит для любых задач, не связанных с криптографией.
    Ответ написан
    Комментировать
  • Имеет ли смысл размещать медиа на .onion-сайте в даркнэте, либо можно ссылаться и на лайтвеб?

    Vamp
    @Vamp
    Вы же зачем-то решили переместить основной сайт в onion? Вот те же самые причины применимы и к поддомену.

    А так, если вы оставите media в интернете, то для доступа к нему будет требоваться использование tor exit ноды, которых мало и они часто бывают перегружены. Поэтому может случиться так, что ваш сайт загрузится быстро, а вот медиа контент медленно и печально. Перенести media в tor стоит хотя бы для избавления от необходимости пересекать границу tor-интернет, тем самым ускорив загрузку.
    Ответ написан
    1 комментарий
  • Как запустить 5000 потоков параллельно с GET запросами?

    Vamp
    @Vamp
    Распараллелить выполнение в самом воркере с помощью ReactPHP или лучше GuzzleAsync. В таком случае не придется держать 5000 воркеров именно

    Вариант с GuzzleAsync - самый лучший. Под капотом он использует возможности curl_multi_exec, которые позволяют асинхронно отправлять несколько запросов, не плодя при этом лишние процессы. Не уверен конечно, что осилит 5000 параллельных запросов, но даже если и не сможет, то можно разделить 5000 между несколькими воркерами.

    2. "Правильно ли" это вообще делать с помощью PHP или это все таки задача уже других языков которые умеют в параллельное выполнение, корутины? Go, NodeJs?

    У вас нагрузка в основном IO bound, так что не имет значения какой язык выбрать. Главное чтобы он поддерживал IO multiplexing (который поддерживается в PHP через вышеупомянутый curl_multi_exec).

    3. Может уже есть готовые решения в виде библиотек на PHP? Искал, но не нашел

    Guzzle
    Ответ написан
    3 комментария
  • Как проверить хэш PHP функции crypt на Python?

    Vamp
    @Vamp
    Есть встроенная библиотека crypt

    from crypt import crypt
    
    print(crypt("hello world", "ab"))
    Ответ написан
    Комментировать