MSI SPATIUM M480 [S78-440L490-P83] 1Тб nvme PCI-E 4.0 x4 устанавливается в M2_1
11999
устанавливается в M2_1 (процессорный)
Apacer AST280 [AP120GAST280-1] 120 ГБ SATA 3
1398 за 2 штуки
Corsair rm650
AMI BIOS7D42vBA
2022-11-11
Ubuntu 22.04
Из особенностей:
все порты и устройства запускаются из коробки, разумеется для Nvidia необходимо ставить фирменный драйвер
периодически подвисает Wifi, модуль успешно сканирует сети и пытается подключиться, но подключение не происходит. не помогает ни смена Wifi точки, ни смена дистрибутива, какая то авппратная проблема и проявляется периодически, в остальное время Wifi работает
первый слот m2 на материнской плате предназначен только для NVME дисков, обычный SATA3.m2 там работать не будет
система охлаждения сильно избыточная, так как ни каким тестами и стрестестами, а так же их комбинациями не удалось разогреть CPU выше 60 градусов
оперативная память переключается на частоты выше 5Ггц в биосе с помощью XMP профилей
при передачен звука через HDMI если вслушиваться то слышен высокочастотный "призвук"
для данного процессора можно использовать специальные, адаптированные linux-ядра (моложе 5.18), которые будут эффективно управлять распределением нагрузки между производительными ядрам и энергоэффективными, для Ubuntu есть репозитори и скрипт для установких новых ядре, но они отказываются загружаться по причине не соответствия каким то подписями и вообще новые ядра начинают весить более 700Мб
Для наглядности приведу три картики илюстрирующих процесс "оцифровки звука"
на частоте 44,1 килогерца, за одну секунде будет получено данных -- 44100 * ширину слова АЦП/ЦАП, например при ширине АЦП 32 бита, за одну секунду будет получено 172 килобайта данных
на частоте 88,2 килогерца, за одну секунде будет получено данных -- 88100 * ширину слова АЦП/ЦАП, например при ширине АЦП 32 бита, за одну секунду будет получено 344 килобайта данных
на частоте 384 килогерца, за одну секунде будет получено данных -- 384000 * ширину слова АЦП/ЦАП, например при ширине АЦП 32 бита, за одну секунду будет получено 1,5 мегабайта
Соответственно, чем выше частота дискретизации и длиннее шина офицровки, тем больше накапливается данных и тем большего качества записывается или воспроизводится звук, тем больше получаются размеры аудио-файлов и большая нагрузка необходима для обработка такого объёма данных
Последняя картинка наглядно поясняет чем отличается цифровой звук от настоящего
# создаёт виртуальный Диск и отображает имя файла виртуального диска, в моём случае /dev/loop15
# список разделов можно посмотреть вот так sudo fdisk -l /dev/loop15
sudo mount /dev/loop15p2 /mnt
# монтирует второй раздел виртуальный диска в директорую /mnt/
# тут какие то работы с данными образами
В инфраструктуре Flask есть фреймворк flask_restful для реализации Rest API и последние несколько лет там начались проблемы с развитием, в результате чего появилось несколько форков. В частности я решил попробовать построить один проект на flask_restx.
В этой заметке я буду описывать, что из этого вышло и насколько это решение хорошо для использования
С помощью RESTX я реализовал следующие API
авторизация на основе JWT токен
обновление JWT токена с помощью Refresh токента
получение и редактирование профиля пользователя
создание точки загрузки файла
загрука файла частями (chunks)
просмотр списка загруженных файлов
просмотр свойств файла по ID
Выглядит хорошо и лаконично, вот например API получения списка публикаций пользователя
Но если смотреть в целом, то приходится для каждой модели базы писать модель сериализации
А ещё больше напрягло то, что фреймворк просто не предлагает ни какого способа пагинации. То-есть, API легко отдаёт всю выборку, а для того чтобы отдать сред выборки в стиле Django, необходимо руками высчитать total и сломать весь красивый механизм marshal_with
Так же, нет интеграции со sqlalchemy, конечно можно найти способ
но как по мне конструкция ModelX.query.filter(**kwargs).all() выглядит так себе
docker run -v $OVPN_DATA:/etc/openvpn --rm kylemanna/openvpn ovpn_getclient USERNAME > USERNAME.ovpn
И всё, можно пользоваться
Чтобы в дальнейшем сохранилась возможность генерировать новые ключи необходимо восстанавливать значение export OVPN_DATA="ovpn-data-example" и использовать passkey использованный для генерации корневого сертификата
Посмотреть статус OpenVPN сервера можно вот так
docker exec -it funny_varahamihira ovpn_status
Если необходимо запустить VPN клиента на постоянной основе, например на ubuntu сервере, то необходимо сгенерировать ключ для этого сервера, скопировать его в директорию /etc/openvpn/client.conf
При сборке на свежей системе может возникнуть ошибка
./configure: error: the HTTP rewrite module requires the PCRE library.
You can either disable the module by using --without-http_rewrite_module
option, or install the PCRE library into the system, or build the PCRE library
statically from the source with Angie by using --with-pcre=<path> option.
Эта ошибка проявляется если сборщик не может найти библиотку перловых регулярных выражений, решается проблема легко
for t in $(echo \\dt | psql $BASE |grep public |awk '{print $3}'); do
echo "SELECT setval('$t"_id_seq"', (select max(id)+1 from $t), true);";
done | psql $BASE
Суть проблемы в том, что при репиликации таблицы значение последовательности таблицы автоматически не меняется, по этому после отключения репликации значение last_insert_id будет отставать от реального количество записей в таблице
после чего сделал nginx reload и сервер начал работать как обычно, но после перезагрузки всего сервера Nginx не запустился и вы давал вот такую ошибку
nginx: [emerg] could not build server_names_hash, you should increase server_names_hash_bucket_size: 32
суть ошибки в том, у nginx по умолчанию определён небольшой размер буфера для хранения и обработки server_name
если определить размер этого буфера через переменную server_names_hash_bucket_size в разделе http файла /etc/nginx/nginx.conf то сервер будет нормально перезапускаться и работать
После неудачного эксперимента с бекапами база данных может содержать по несколько копий каждой строки таблицы, это приводит любой ORM в ступор, впрочем и руками удалить такие записи не полуться, так записи имеют одинаковые ID. Ниже решение как легко удалить дубли и оставить только по одной уникальной строке
table_name=auth_users
data_base=breys
echo "
begin;
select count(1) from $table_name ;
create table ttt as select distinct id x, * from $table_name ;
alter table ttt drop column x;
truncate table $table_name;
insert into $table_name (select * from ttt );
drop table ttt ;
select count(1) from $table_name ;
end;
" | psql $data_base
Суть метода такова:
создать копию таблицы содержающую только уникальные по ID записи, для этого используется DISTINCT,
затем нужно удалить сигнальное поле x
почистить целевую таблицу
затем перенести данные из временной таблицы в целевую
удалить временную таблицу
Если необходимо обработать все таблицы базы данных то скрипт можно использовать в цикле
for table_name in $(echo '\dt' | psql $data_base | awk '{print $3}'| grep -v ^$|sort ); do
echo "
begin;
select count(1) from $table_name ;
create table ttt as select distinct id x, * from $table_name ;
alter table ttt drop column x;
truncate table $table_name;
insert into $table_name (select * from ttt );
drop table ttt ;
select count(1) from $table_name ;
end;
" | psql $data_base;
done
с помощь транзакций можно предовратить удаление данных в случае проблемного импорта
Задача реализовать прозрачное связывание "союзами" пользователей сайта. Такое необходимо когда пользователь А запросил союз у пользователя Б и тот одобрил этот союз, тогда у обоих пользователей должен обновиться список союзников и табличная связь будет выглядеть следующим образом
таблица пользователей
таблице связей
1
осёл
2
козёл
3
мишка
4
пятачёк
5
винипух
1
2
1
3
4
5
Связав таблицы где 1 колонка это номер строки хозяин, а вторая колонка это номер строки союзника получется, что у осла в союзниках козёл и мишка, а у пятачка союзник только винипух винипух
С точки зрения базы данных это связь многие ко многим и на Sqlalchemy решается через создание ассоциативной таблиц, а учитывая что помимо союзной связи необходимо сохранить состояние связи и даты создания и обновления, то ассоциативная таблица превращается в полноценную модель
class Union(db.Model):
__tablename__ = "user_unions"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
user1_id = db.Column(db.Integer, db.ForeignKey('users.id'), primary_key=True)
user2_id = db.Column(db.Integer, db.ForeignKey('users.id'), primary_key=True)
created = db.Column(db.DateTime(timezone=True), server_default=func.now())
updated = db.Column(db.DateTime(timezone=True), onupdate=func.now())
enable = db.Column(db.Boolean, default=False, nullable=False)
def __repr__(self):
if self.enable:
return "союз с {} заключён".format(self.user2)
return "союз с {} не подписан".format(self.user2)
class User(db.Model):
__tablename__ = "users"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(40), unique=False, nullable=False)
email = db.Column(EmailType, unique=False)
def add_user(self, user):
""" добавление союза с user"""
union = Union(user1=self, user2=user)
db.session.add(union)
db.session.flush()
Всё будет прекрасно до тех пор пока не потребуется у объектов User обратиться к списку союзных пользователей. Дело в том, что метол обращения к списку союзников выглядит по разному для разныз пользователей. Если для того чтобы узнать список союзников осла неоходимо выбрать все вторые колонки в строка в которых в первой колонке номер строки осла, а чтобы выбрать союзников козла, необходимо выбрать все первые колонки в строках где вторая колонка равна номеру строки козла. Таки образом получается метод выбора союзников осла и козла будет разный, а это не красиво.
Но всё таки можно реализовать универсальный метод поиск союзников для каждого пользователя и в SQL виде он будет выглядеть вот так
select *
from users
where id in (
select user2_id id
from user_unions
where user1_id = 1
union
select user1_id id
from user_unions
where user2_id = 1
)
тут производится выборка id союзников в ассоциативной таблице для обоих типов запросов, затем результаты объединяются и используются во вложенном запросе при обращении к таблице пользователей.
Sqlalchemy позволяет реализовать и такой достаточно сложный запрос с помощью объектного ORM и тогда метод выбора союзников пользователя будет выглядет следующим образом
и при переходе на домен перекидывало на предложение о покупке домена за 3695 долларов (на момент покупки это 276 430 рублей).
Поиск отзывов на этот сервис в рунете подтвредил сомнения о том, что это сайт мошеннический, но я обратил внимание на то, что в рунете не было ни одного упоминания, что ктото заплатил за домен и не получил ни домена ни денег. Поиск отзывов на американских форумах подтвердил мысль, о том, что люди очень недовольны что их забытые домены выкупают за $5, а затем предлагают купить им же за $1500, всех смушают цены, но очевидно, что некоторым приходилось выкупать свои домены.
Так же из этих форумов стало известно, что hugedomains.com находится на одном гео.адресе с namebright.com, а hugedomains.com это сервис аренды доменов. То-есть там выстроена схема в которой пользователи покупают и используют домен на namebright.com, а когда домен освобождается (например, в случае когда хозяин забыл оплатить), домен передаются в hugedomains.com, а там работает автоматизированная система продажи домена. У домена настраивается редирект на hugedomains.com, там открывается предложение о покупке и форма ввода данных, включая номер карты и cvv код
Попытки переписываться с компанией приводят к тому, что они высылают электронный счёт к оплате, после которого якобы передадут управление доменов. Для получения управления необходимо завести учётную запись на namebright.com
После оплаты счёта, мы в своём кабинете на namebright.com получили полный контроль над доменом, заменили DNS сервера и домен работает. Остаётся лишь перенести домен к нашим хостерам