• Как сделать список destination в iptables?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Например, так:

    iptables -t mangle -N SPISOK
    iptables -t mangle -A SPISOK -d 10.9.0.0/24 -j RETURN
    iptables -t mangle -A SPISOK -d 10.11.0.0/24 -j RETURN
    iptables -t mangle -A SPISOK -d 10.14.0.0/24 -j RETURN
    iptables -t mangle -A SPISOK -j MARK --set-mark 4
    iptables -t mangle -A PREROUTING -i enp1s0 -s 10.8.0.0/24 -j SPISOK
    Ответ написан
    Комментировать
  • Как изменить текст в консоли питона?

    Daemon23RUS
    @Daemon23RUS
    Из простого (в строке)
    print('|о----|', end='\r', flush=True)
    time.sleep(5)
    print('|----o|', end='\r', flush=True)

    из библиотек sys stdout tqdm rich curses
    Ответ написан
    Комментировать
  • Как сделать грамотный счетчик в питоне?

    grantur5707
    @grantur5707
    Full Stack Web Developer
    По феншую и правильно по хорошему бы реализовать класс, в котором будешь хранить состояние счётчиков

    import subprocess
    from time import sleep
    
    class CameraMonitor:
        def __init__(self):
            self.IP12 = '192.168.0.100'
            self.IP13 = '192.168.0.101'
            self.RODOS12 = '192.168.1.100'
            self.RODOS13 = '192.168.1.101'
            
            self.fail_count = {'Купол 12': 0, 'Купол 13': 0}
            self.reboot_count = {'Купол 12': 0, 'Купол 13': 0}
    
        def ping_camera(self, ip):
            cmd = f'ping {ip} -n 1 -w 100'
            response = subprocess.call(cmd, stdout=subprocess.DEVNULL)
            return response == 0
    
        def cameras_checker(self):
            r_dict = {'Купол 12': self.IP12, 'Купол 13': self.IP13}
            while True:
                for camera, ip in r_dict.items():
                    if self.ping_camera(ip):
                        print(f'Camera {camera} - OK')
                        self.fail_count[camera] = 0
                    else:
                        self.fail_count[camera] += 1
                        print(f'Camera {camera} - Died')
    
                        if self.fail_count[camera] >= 5:
                            self.cameras_reboot(camera)
    
                sleep(5)
    
        def cameras_reboot(self, camera):
            if camera == 'Купол 12':
                ip = self.RODOS12
            else:
                ip = self.RODOS13
            
            self.reboot_count[camera] += 1 
            print(f'Rebooting {camera} at IP {ip}')
    
        def info(self):
            for camera, count in self.reboot_count.items():
                print(f'Перезагрузок {camera}: {count}')
    
    
    if __name__ == "__main__":
        monitor = CameraMonitor()
        monitor.cameras_checker()
    Ответ написан
    3 комментария
  • Как получить битовое представление скрина для передачи через сокет, не сохраняя его?

    vollossy
    @vollossy
    Веб-разработчик с небольшим опытом работы
    Для изображений с компрессией (скорее всего, вы работаете jpeg, png или чем-то ещё), можно использовать метод Image.save(fp: str | bytes | PathLike[str] | PathL..., передав в качестве параметра fp экземпляр BytesIO.

    В принципе, для работы с байтами в памяти программы, рекомендую использовать этот класс, весьма удобно.
    Ответ написан
    Комментировать
  • Как можно оптимизировать этот код?

    Vindicar
    @Vindicar
    RTFM!
    Для начала определи, что у тебя занимает время - скачивание, или парсинг. Подходы будут разные.
    Если хочется в лоб решать задачу - то multiprocessing в руки, даёшь дочернему процессу URL, он тебе возвращает структуру данных. Главный процесс раздаёт URLы и собирает ответы в какое-то итоговое хранилище.
    Пример работы с пулом процессов.
    Ответ написан
    Комментировать
  • Как можно оптимизировать этот код?

    fox_12
    @fox_12 Куратор тега Python
    Расставляю биты, управляю заряженными частицами
    Все не смотрел, но простыни типа:
    def get_contact(ids):
        for id in ids:
            template = f'https://etender.gov.az/api/events/{id}/contact-persons'
            try:
                response = requests.get(template, timeout=20)
                if response.status_code == 200:
                    data_list = response.json()
                    for data in data_list:
                        main_data['Full_name'].append(data.get('fullName', 'None') if data.get('fullName') else 'None')
                        main_data['Contact'].append(data.get('contact', 'None') if data.get('contact') else 'None')
                        main_data['Position'].append(data.get('position', 'None') if data.get('position') else 'None')
                        main_data['Phone_number'].append(data.get('phoneNumber', 'None') if data.get('phoneNumber') else 'None')
    
                else:
                    main_data['Full_name'].append('None')
                    main_data['Contact'].append('None')
                    main_data['Position'].append('None')
                    main_data['Phone_number'].append('None')
            except requests.Timeout:
                main_data['Full_name'].append('None')
                main_data['Contact'].append('None')
                main_data['Position'].append('None')
                main_data['Phone_number'].append('None')


    пишутся гораздо проще. Да и структуру данных я бы поправил. К примеру простыня выше заменяется более лаконичным кодом:
    main_data = []
    ...
    
    def get_contact(ids):
        for id in ids:
        	current_data = {'Full_name': 'None', 'Contact': 'None', 'Position': 'None',  'Phone_number': 'None'}
            template = f'https://etender.gov.az/api/events/{id}/contact-persons'
            try:
                response = requests.get(template, timeout=20)
                if response.status_code == 200:
                    data_list = response.json()
                    for (elem_to, elem_from) in [
                         ('Full_name', 'fullName'),
                         ('Contact', 'contact'),
                         ('Position', 'position'),
                         ('Phone_number', 'phoneNumber')
                    ]:
                    	current_data[elem_to] = data.get(elem_from, 'None')
             except requests.Timeout:
                   pass
            main_data.append(current_data)
    Ответ написан
    Комментировать
  • Как отобразить даты в виде недельного интервала?

    Geleoss
    @Geleoss
    Любитель таблиц
    66deeb597c61e326369648.pngДата понедельника на текущей неделе:
    mon; TODAY()-WEEKDAY(TODAY();3)
    Дата в на текущей неделе:
    sun; TODAY()-WEEKDAY(TODAY();3)+6
    Даты недели:
    1. TO_TEXT(mon) & "-" & TO_TEXT(sun)
    2. TEXT(mon;"dd.mm") & "-" & TEXT(sun; "dd.mm")
    Пример.
    Ответ написан
    1 комментарий
  • Как в Obsidian увеличть ширину заметки?

    @oghmios
    Можно не править CSS, а просто отключить конфигурационный параметр "Ограничить максимальную длину строки":

    Настройки (иконка "шестерёнка" внизу слева) -> Редактор -> Отображение -> выключить переключатель "Ограничить максимальную длину строки"

    На английском это "Readable file length", эта настройка появилась ещё в версии 0.7.0: https://obsidian.md/changelog/2020-06-09-desktop-v...
    https://readmedium.com/obsidian-editor-settings-fo...
    Ответ написан
    1 комментарий
  • Как с помощью JS организовать запись и чтение данных?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    GM_setValue GM_getValue - будут храниться в сторе самого расширения.

    Всякие куки, localStorage, indexedDb - всё может почитститься самом сайтом или случайно тобой.

    Надёжнее - только свой сервак завести и к нему запросами отправлять-получать.:)
    Ответ написан
    Комментировать
  • Почему все говорят что писать ботов это сложно?

    Vindicar
    @Vindicar
    RTFM!
    А сложность начинается, как только задачи, стоящие перед ботом, перерастают уровень примера в документации видеотуториале пятилетней давности.

    Нужно сделать несколько под-команд у команды. Напишу цепочку if-elif-else, делов то. Ой, а теперь простыня кода на пять экранов, в которой фиг чего найдёшь. Потому что нет привычки структурировать код.

    Нужно, чтобы несколько команд/событий формировали цепочку (сценарий). Например, пользователь отправил тре сообщения, первое с именем, второе с возрастом, третье с адресом. Ой, а как это сделать вообще? Не зная понятия "конечный автомат" (finite state machine, FSM), очень трудно догадаться, как тут поступить.

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

    Нужно, чтобы бот выполнил длительную задачу, и написал сообщение, когда она выполнится. Не вопрос, напишу функцию, вызову её, а сразу после отправлю сообщение. Ой, а бот не отвечает! Потому что рабочий цикл asyncio занят этой длительной операцией и не может отреагировать на поступающие данные. Нужно иметь хорошее представление о том, как работает асинхронная программа.

    Нужно добавить боту графический интерфейс - админку. Ой, а работает или интерфейс, или сам бот! Потому что нужно представлять, как устроено большинство GUI-фреймворков, и как устроена асинхронное приложение. А заодно понимать многопоточность, вопросы синхронизации действий между двумя потоками, и особенности работы с asyncio в многопоточных приложениях. Потому что одним потоком тут обойтись будет очень непросто.

    Нужно хранить данные в БД. Ой, а почему у меня проблемы при записи в БД имени пользователя? А потому что погромист собирает SQL-запрос через форматирование строк. Надо было почитать доки, чтобы наткнуться на prepared statements, они же parameterized queries.

    Нужно хранить данные в БД. Вот только данные имеют связи многие-ко-многим. Я знаю! Я буду просто добавлять или удалять столбцы в таблицу! Потому что не освоены даже азы проектирования БД. Тут уже nuff said. И да, я такое видел на этом сайте.

    Незнание средств языка и основных приемов построения алгоритмов и структур данных приводит к диким велосипедам, которые создают больше проблем, чем пользы. Особенно если к этому добавляется нежелание находить и читать документацию на фреймворк, на котором построен бот.
    Ответ написан
    2 комментария
  • Как в sql прибавить число и сравнить с другим?

    @Zzzz9
    Ответ написан
    Комментировать
  • Как сделать резервное копирование archlinux?

    @aleks-th
    Вы сначала делаете:
    1. Cписок то чего бекапим.
    2. Когда бекапим.
    3. С какой периодичностью бекапим.
    4. Как проверяем что бекап корректен.
    5. Определяем сколько времени должны хранится бэкапы.
    6. В боевом режиме бэкапим когда идет доступ к файлам или во время простоя.
    7. Какое время критично для развертывания этих бэкапов( примерное время которое может без потерь простаивать сервер пока идет восстановление данных)
    8. Чем бэкапим - базы данных свои инструмент, файлы можно просто tar архивировать и так далее.
    9. Сколько резервных копий и где храним.
    10. Обязательно оцениваем примерные обьемы, будет плохо если тупо на третьем бэкапе диск кончится или в облаке место....

    Далее настраиваем cron и какие-нить rsync или rclone.
    Потом скрипт для проверки целостности данных - прошел бекап или нет - живые там файлы или нет, не проверяя этого нет смысла вообще что-то бэкапить, нужно убеждаться что все работает, а то потом обнаружишь что бэкапы есть но не читаются изза какогонить глюка и это будет эпик фейл...
    И вуаля - у вас все настроено.

    Но, если речь идет о том что тупо систему скопировать свою ни в чем не разбираясь, и после обновления откатится до предыдущей версии.
    Все что выше можно не читать, тупо взять какойнибудь Acronis и делать тупо копии всего диска перед тем как будешь делать какието глобальные изменения, ну или по расписанию.
    Ответ написан
    Комментировать
  • Как ускорить YouTube на OpenWRT?

    ValdikSS
    @ValdikSS
    Я установил на роутер zapret nfqws, не используя стандартные скрипты из поставки. Конфигурация такая, какая описана вот в этом баге:

    https://github.com/bol-van/zapret/discussions/262

    Взял бинарник из репозитория, написал простейший init-скрипт (/etc/init.d/nfqws) для openwrt с вшитыми параметрами, написал свои правила firewall’а. Оригинальные тоже хорошие (и обрабатывают разные конфигурации), но вот эти банально проще.

    # cat /etc/init.d/nfqws 
    #!/bin/sh /etc/rc.common
    
    USE_PROCD=1
    START=91
    
    PROG=/etc/zapret/nfqws/nfqws
    
    start_service() {
      procd_open_instance
      procd_set_param command "$PROG"
      procd_append_param command --dpi-desync=fake
      procd_append_param command --dpi-desync-fooling=md5sig,badseq
      procd_append_param command --dpi-desync-split-pos=1
      procd_append_param command --dpi-desync-repeats=12
      procd_append_param command --dpi-desync-ttl=4
      procd_append_param command --qnum=200
      procd_append_param command --hostlist=/etc/zapret/nfqws/youtube.txt
    #  procd_append_param command --hostlist=/tmp/domains-export.txt
      procd_set_param stdout 1 # forward stdout of the command to logd
      procd_set_param stderr 1 # same for stderr
      procd_close_instance
    }


    С моими правилами файрволла (connbytes) в nfqws копируются только первые 8 пакетов, а дальше всё маршрутизируется как обычно. /etc/zapret/zapret.nft:

    chain zapret_lan_hook {
        type filter hook forward priority mangle;
    
    #    iifname {"br-lan"} \
          ip daddr != {0.0.0.0/8, 10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, 100.64.0.0/10, 169.254.0.0/16, 224.0.0.0/3, 255.255.255.255/32} \
          tcp dport {80, 443} ct original packets lt 8 counter queue flags bypass to 200 comment "zapret IPv4 443 tcp"
    
    #    iifname {"br-lan"} \
          ip6 daddr != {::ffff:0:0/96, fc00::/7, fe80::/10, ff00::/8} \
          tcp dport {80, 443} ct original packets lt 8 counter queue flags bypass to 200 comment "zapret IPv6 443 tcp"
    
    #    iifname {"br-lan"} \
          ip daddr != {0.0.0.0/8, 10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, 100.64.0.0/10, 169.254.0.0/16, 224.0.0.0/3, 255.255.255.255/32} \
          udp dport 443 ct original packets lt 8 counter queue flags bypass to 200 comment "zapret IPv4 443 udp"
    
    #    iifname {"br-lan"} \
          ip6 daddr != {::ffff:0:0/96, fc00::/7, fe80::/10, ff00::/8} \
          udp dport 443 ct original packets lt 8 counter queue flags bypass to 200 comment "zapret IPv6 443 udp"
    }


    Нужно заinclude’ить скрипт в настройках firewall’а. /etc/config/firewall:

    config include 'zapret'
    	option type 'nftables'
    	option path '/etc/zapret/zapret.nft'
    	option position 'table-post'
    	option enabled '1'


    Необходимо отключить offloading, с ним, скорее всего, работать не будет (но я не проверял, оригинальные правила учитывают этот момент).

    В таком виде всё установить можно на ЛЮБОЙ роутер, даже на 4/32, при большом желании (скриптом скачивания бинарника в оперативную память, при необходимости).

    /etc/zapret/nfqws/youtube.txt:

    youtube.com
    youtu.be
    googlevideo.com
    googleapis.com
    gvt1.com
    ggpht.com
    ytimg.com
    youtube-nocookie.com
    play.google.com
    video.google.com
    youtube-ui.l.google.com
    youtubeeducation.com
    youtubekids.com
    Ответ написан
    2 комментария
  • Как вычислить количество записей?

    Vindicar
    @Vindicar
    RTFM!
    Прочитать все записи, разбить строку по разделителю, скормить всё в collections.Counter.
    С pandas не работал, вот пример для списков:
    from collections import Counter
    from itertools import chain
    data = [
      (1, 'old;white'),
      (2, 'old;green'),
      (3, 'old;brown'),
      (4, 'new;green'),
    ]
    # генерирует последовательность ['old', 'white'], ['old', 'green'], ...
    split_generator = (item[1].split(';') for item in data) 
    # генерирует последовательность 'old', 'white', 'old', 'green', ...
    property_generator = chain.from_iterable(split_generator)
    # исправляет регистр и удаляет пробелы - можно убрать, если не надо
    property_fixed_generator = (item.strip().lower() for item in property_generator)
    # поглощает данные из генераторов и считает вхождения
    count = Counter(property_fixed_generator)
    print(count)  # Counter({'old': 3, 'green': 2, 'white': 1, 'brown': 1, 'new': 1})
    Ответ написан
    Комментировать
  • Как выполнить относительный импорт библиотеки в Python?

    @o5a
    Можно добавить путь верхнего уровня (project_catalog) к pythonpath, тогда можно будет использовать относительный импорт. Например так
    import os
    
    # выходим на верхний уровень
    parentdir = os.path.dirname(os.path.dirname(__file__))
    # и добавляем его к путям поиска
    os.sys.path.insert(0,parentdir)
    # после чего можем использовать импорт по вложенному пути
    import module_name.module.ModuleFileOne
    Ответ написан
    1 комментарий
  • Как добавить класс js?

    Rsa97
    @Rsa97
    Для правильного вопроса надо знать половину ответа
    Используйте всплытие событий. Вешайте обработчик на постоянно присутствующий родительский элемент.
    Ответ написан
    2 комментария
  • Как получить высоту только видимой части блока?

    delphinpro
    @delphinpro Куратор тега CSS
    frontend developer
    простая математика. исходные данные: координаты блока относительно окна браузера (elemtnt.getBoundingClientRect()) и высота окна (window.height).

    Если y_top <= 0 и y_bottom >= window.height То высота видимой части блока равна высоте экрана (первая ваша картинка).
    Если y_top > 0 и y_bottom < window.height То высота видимой части блока равна высоте это блока (весь виден).
    Если y_top > 0 и y_bottom > window.height То высота видимой части блока равна высоте экрана минус верхняя позиция (вторая картинка).
    Если y_top < 0 и y_bottom < window.height То высота видимой части блока равна значению нижней позиции (третья картинка).
    Ответ написан
    1 комментарий
  • Какую использовать утилиту на linux для создания waweform?

    Viktor_T2
    @Viktor_T2
    python developer
    Утилита для линукс bbc audiowaveform https://github.com/bbc/audiowaveform
    audiowaveform -i test.mp3 -o test.png -z 10000 --waveform-style bars --bar-width 3 --bar-gap 2 --bar-style rounded --no-axis-labels --amplitude-scale 1.25 --background-color 333333 --waveform-color BFBFBF

    654809df5e4da286885586.png
    Ответ написан
    Комментировать
  • Как ловить статус и от этого выводить результат?

    Vindicar
    @Vindicar
    RTFM!
    Вместо строки возвращай кортеж или словарь. Короче, структуру данных.
    from typing import NamedTuple
    
    class Result(NamedTuple):
        text: str  # текст запроса
        success: bool  # успешен ли запрос
        status: str  # статус
    
    async def check_text(text: str) -> Result:
        url = f'https://сайт.com/?query={text}'
    
        async with aiohttp.ClientSession() as session:
            async with session.get(url) as response:
                if response.status != 200:
                    return Result(text=text, success=False, status='Не удалось определить результат')
                html = await response.text()
                soup = BeautifulSoup(html, 'html.parser')
                status_element = soup.find('div', class_='table-block')
                if not status_element:
                    return Result(text=text, success=False, status='Не удалось определить результат')
                status_text = status_element.get_text().strip()
                # тебе нужно будет решить, когда запрос был успешен (True), а когда нет (False)
                if "ok" in status_text:
                    return Result(text=text, success=True, status='Можно')
                elif "no" in status_text:
                    return Result(text=text, success=False, status='Данный вариант недоступен')
                elif "no1" in status_text:
                    return Result(text=text, success=True, status='Можно под заказ')
                else:
                    return Result(text=text, success=False, status='Неизвестно')

    Тогда можно будет анализировать результат просто:
    result = await check_text(text)
    if result.success:
        ...  # реагируем на успешный запрос
        logger.info('%s: %s', result.text, result.status)
    else:
        ...  # реагируем на неудачный запрос
        logger.info('%s: %s', result.text, result.status)
    Ответ написан
  • Как сделать автозапуск python программы с виртуальным окружением в фоновом режиме на линукс?

    drygdryg
    @drygdryg
    Python-разработчик
    Можно использовать систему инициализации Systemd. Напишите unit-файл такого вида:
    [Unit]
    Description=My Script Service
    After=multi-user.target
    
    [Service]
    User=user  # Имя пользователя, от имени которого будет запускаться команда, указанная в ExecStart
    WorkingDirectory=/home/user/program  # Директория, в которую будет осуществлён переход перед запуском
    ExecStart=/home/user/program/venv/bin/python /home/user/program/webui.py
    Restart=always  # Всегда перезапускать скрипт при его падениях
    
    [Install]
    WantedBy=multi-user.target

    и сохраните его в директории /etc/systemd/system с расширением .service, например, /etc/systemd/system/my_program.service.

    Здесь не используется скрипт activate для активации виртуального окружения, но вместо этого указывается полный путь к интерпретатору Python внутри этого виртуального окружения.
    Также важно указывать абсолютные пути к файлам и директориям, даже несмотря на то, что задана рабочая директория WorkingDirectory.
    Если ваш скрипт опирается на сетевые соединение, в секции Unit в качестве After задайте network-online.target вместо multi-user.target:
    After=network-online.target

    После этого перезагрузите конфигурацию Systemd:
    sudo systemctl daemon-reload
    И запустите сервис с добавлением в автозагрузку:
    sudo systemctl enable --now my_program.service
    Ответ написан
    2 комментария