LINUX.ORG.RU

Сообщения KivApple

 

mojiverse

Форум — Talks

Запилил гибрид игры «Жизнь» и всяких коллективных онлайн рисовалок типа pxls.space под соусом эмоджи.

Используются классические правила - если у эмоджи 2-3 соседа, он живёт, если меньше, умирает от одиночества, если больше, от перенаселения. Если у пустой клетки есть 3 соседа эмоджи, то там спаунится новый эмоджи (выбирается по большинству соседей).

Для большего интереса центр поля защищён от изменений игроками, но вы можете строить глайдеры и ружья по краям, которые будут проникать в центр.

Для защиты от вайпов и прочих злоупотреблений количество эмоджи, которое можно поставить постепенно растёт по мере того как вкладка с игрой активна и в фокусе.

Бек написан на Rust, фронт на TypeScript, крутится всё это на подкроватном сервере на Ubuntu. И играть в это, очевидно, тоже можно из-под Linux, если имеется в наличии любой современный браузер.

Ссылка: https://mojiverse.art/

 mojiverse, игра жизнь, пет проект

KivApple
()

«Три в ряд» с античитом

Форум — Development

Предупреждаю, мне хочется очень странного.

Я хочу алгоритм генерации поля «три в ряд» (как начального состояния, так и заполнения новыми фишками, когда игрок сделал ход). На игровом поле есть обычные фишки и есть бонусы. Игрок получает отдельный очки за удаление обычных фишек и за удаление бонусов. Важна именно сумма собранных бонусов, очки за обычные фишки не принципиальны.

При этом алгоритм генерации должен быть особым. А именно: вначале игры с сервера получается некий seed поля (это может быть что-угодно, хоть один Long, хоть несколько килобайт данных) и затем используется. При этом сервер заранее знает, сколько максимум можно собрать бонусов на поле за всю партию (есть ограничение по времени, а зная длительности анимаций ходов, можно пересчитать это и в ограничение по ходам за партию). Например, он сначала генерирует количество бонусов, а уже потом создаёт seed из него.

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

При этом клиент не должен иметь возможности (должно быть вычислительно сложной задачей) по seed алгоритмически вычислить минимальное и максимальное число очков. Нужно по-честному играть.

Например, можно обеспечить это дорогим алгоритмом регенерации поля после хода. Таким образом, чтобы нельзя было перебрать все варианты на много шагов вперёд и найти оптимальный. Можно также как-то по-особому генерировать поле, чтобы плодить варианты и их было слишком много перебирать.

Можно немного модифицировать геймплей самого «Три в ряд» (вводить фишки с особыми эффектами, увеличивающими неопределённость), если это необходимо для достижения цели.

Короче, надо защититься от потенциального читерства а-ля «расковыряли API и просто спамим сервер запросами о том, что набрали максимум бонусов».

Возможно ли такое хотя бы теоретически? В какую сторону копать?

 ,

KivApple
()

Docker Overlay Network + Tailscale VPN

Форум — Admin

Есть несколько серверов объединённых в одну виртуальную сеть с помощью Tailscale VPN. На них установлен Docker и все сервера объединены в Docker Swarm, при этом от Docker Swarm используются лишь overlay network, без всего остального - контейнеры запускаются обычным docker compose.

Есть несколько overlay network созданных вручную с флагом attachable. В compose эти сети прописаны как external и некоторые контейнеры их используют.

На двух серверах из трёх всё работает хорошо - но там меньше десятка контейнеров на каждом. А вот на третьем сервере контейнеров 25 (и чуть ли не половина из них подключена к той или иной overlay network).

При перезагрузке стабильно не могут запустится (они запускаются за счёт restart=unless-stopped) 2-3 контейнера из числа тех, которые подключены к overlay network. Каждый раз это разные контейнеры.

Статус у них:

failed to set up container networking: attaching to network failed, make sure your network options are correct and check manager logs: context deadline exceeded

Если вручную сделать им docker compose up, они успешно стартуют.

Но мне то нужна автоматика - сервер должен сам поднять все сервисы в рабочее состояние после ребута.

В данный момент единственная кастомизация докера - добавление ему зависимости от tailscale в systemd юнит:

$ cat /etc/systemd/system/docker.service.d/override.conf 
[Unit]
Requires=tailscaled.service network-online.target
After=tailscaled.service network-online.target

[Service]
ExecStartPre=/bin/sh -c 'until ip link show tailscale0 >/dev/null 2>&1; do echo "Waiting for tailscale0 interface..."; sleep 1; done; until [ "$(tailscale status --json | jq -r .BackendState)" = "Running" ]; do echo "Waiting for Tailscale..."; sleep 1; done'

Это решило проблему, что зависимые от оверлейной сети контейнеры вообще не стартовали, но осталась проблема, что парочка случайных контейнеров не может стартовать на сервере, где их много.

Проблема усугубляется тем, что ошибка создания контейнера не считается его падением и restart не срабатывает.

UPD: Вроде решил с помощью:

$ cat /etc/systemd/system/docker.service.d/override.conf 
[Unit]
Requires=tailscaled.service network-online.target
After=tailscaled.service network-online.target

[Service]
ExecStartPre=/bin/sh -c 'until ip link show tailscale0 >/dev/null 2>&1; do echo "Waiting for tailscale0 interface…"; sleep 1; done; until [ "$(tailscale status --json | jq -r .BackendState)" = "Running" ]; do echo "Waiting for Tailscale…"; sleep 1; done'
ExecStartPost=/bin/bash -c 'sleep 30 && docker start $(docker ps -a -q --filter status=exited --filter status=created)'

Но непонятно насколько надёжно. Нет ли решений лучше.

 ,

KivApple
()

SwarmChatBot

Форум — Talks

Вдохновился Посоветуйте идею для TG-бота, которая минимум полезна и максимум можно продать как успеховую. и запилил за сегодняшний вечер небольшого Telegram бота.

Задумка проста. Добавляете бота в групповой чат. Пишете сообщение тегая бота (он не имеет доступа к сообщениям). Сообщение улетает в другой случайно выбранный чат, куда кто-то другой добавил этого бота.

Если кто-то в этом чате реплайнет на это сообщение, то ответ будет переслан назад в чат отправителя. Если зареплаить реплай, то реплай уйдёт в чат получателя и так далее. То есть поддерживается полноценная нить диалога между двумя чатами, но скрывается собственно какие это два чата и имена собеседников (и так как это чаты групповые, то отвечать могут разные люди знакомые между собой с одного конца).

В принципе бот работает и в личке, но моя больная фантазия рисует что-то типа, мол в групповых чатах должно быть веселее.

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

Бот написан на Rust с Teloxide и запущен на сервере под убравлением Ubuntu.

UPD: Бот переименован

 

KivApple
()

Использование UUIDv7 в качестве токена авторизации

Форум — Development

UUID v4 не рекомендуется использовать в качестве токенов авторизации: https://security.stackexchange.com/questions/157270/using-v4-uuid-for-authent...

Do not assume that UUIDs are hard to guess; they should not be used as security capabilities (identifiers whose mere possession grants access), for example. A predictable random number source will exacerbate the situation.

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

Но тем не менее я даже UUID v4 не хочу использовать, не то что криптостойкий рандом в качестве токена авторизации - я буду хранить токены в Postgres, а Postgres, поговаривают, плохо работает с UNIQUE колонками со случайными данными - B-дерево распухает.

Хочу использовать в качестве токенов авторизации UUID v7 - они должны быть по заверению авторов дружелюбны к индексам баз данных. Но беда в том, что их ещё проще угадать, ибо там половина бит даже не рандом неизвестного качества, а вообще метка времени.

Но что если в БД хранить UUID, а юзеру отдавать и от юзера принимать JWT, где UUID хранить в JTI (ну и срок жизни токена, если надо, в exp зашить, stateless фичами JWT мы пользоваться всё равно не будем, нам от него по сути только цифровая подпись токена нужна).

Теперь злоумышленнику мало угадать UUID, ему ещё надо его подписать секретом приложения, который он не знает (в качестве небольшого бонуса - если утечёт дамп БД - без конфига приложения он всё равно не позволит угнать сессии). И наоборот, если утёк секрет JWT, чтобы увести сессию надо ещё угадать UUID (что не невозможно, но всё равно требует усилий). С другой стороны, приложение выборку из БД делает по jti, который UUID v7, который хорошо дружит с индексами БД.

Что думаете о такой схеме?

 ,

KivApple
()

Rust + WGPU + dyn trait

Форум — Development

Есть небольшой рабочий набросок кода, который комплируются и запускается, создавая окно winit и instance + surface wgpu:

use std::sync::Arc;
use winit::event_loop::EventLoop;
use winit::application::ApplicationHandler;
use winit::event::WindowEvent;
use winit::event_loop::{ActiveEventLoop, ControlFlow};
use winit::window::{Window, WindowId};

trait Renderer<'window> {
}

struct WGPURenderer<'window> {
	instance: wgpu::Instance,
	surface: wgpu::Surface<'window>
}

impl<'window> WGPURenderer<'window> {
	async fn new(window: Arc<Window>) -> anyhow::Result<Self> {
		let instance = wgpu::Instance::default();
		let surface = instance.create_surface(Arc::clone(&window))?;
		Ok(Self {
			instance,
			surface
		})
	}
}

impl<'window> Renderer<'window> for WGPURenderer<'window> {
}


#[derive(Default)]
struct App<'window> {
	window: Option<Arc<Window>>,
	renderer: Option<WGPURenderer<'window>>
}

impl ApplicationHandler for App<'_> {
	fn resumed(&mut self, event_loop: &ActiveEventLoop) {
		if self.window.is_none() {
			let window_attrs = Window::default_attributes();
			let window = Arc::new(
				event_loop.create_window(window_attrs).
					expect("Failed to create window")
			);
			self.window = Some(window.clone());
			let renderer = pollster::block_on(WGPURenderer::new(window))
				.expect("Failed to create renderer");
			self.renderer = Some(renderer);
		}
		event_loop.set_control_flow(ControlFlow::Wait);
	}
	
	fn window_event(
		&mut self,
		event_loop: &ActiveEventLoop,
		_window_id: WindowId,
		event: WindowEvent
	) {
		match event {
			WindowEvent::CloseRequested => {
				event_loop.exit();
			}
			_ => {}
		}
	}
}

fn main() {
	let event_loop = EventLoop::new()
		.expect("Failed to create event loop");
	let mut app = App::default();
	event_loop.run_app(&mut app)
		.expect("Failed to start event loop");
}

Проблема в том, что я хочу добавить косвенность - я не хочу прибивать гвоздями App к WGPURenderer, я хочу сделать возможными в будущем написать разные реализации трейта Renderer - например, VulkanRenderer, OpenGLRenderer и т. д.

Но стоит мне сделать:

#[derive(Default)]
struct App<'window> {
	window: Option<Arc<Window>>,
	renderer: Option<Arc<dyn Renderer<'window>>> // Тут может быть и Box
}

...

let renderer = pollster::block_on(WGPURenderer::new(window))
	.expect("Failed to create renderer");
self.renderer = Some(Arc::new(renderer));

Я получаю:

error: lifetime may not live long enough
  --> src/main.rs:29:25
   |
17 |     fn resumed(&mut self, event_loop: &ActiveEventLoop) {
   |                --------- has type `&mut App<'1>`
...
29 |             self.renderer = Some(Arc::new(renderer));
   |                                  ^^^^^^^^^^^^^^^^^^ coercion requires that `'1` must outlive `'static`

Как правильно организовать архитектуру приложения, чтобы можно было иметь общий код App (где расположен код обработки событий ввода и т. п.) на все бекэнды рендера с учётом того, что WGPU требует лайфтайм окна?

 ,

KivApple
()

Counter в Grafana

Форум — Admin

Есть приложение, в нём есть метрики-счётчики (counter), которые собираются в Prometheus, которые потом выводятся на графиках в Grafana.

Проблема в том, что рестарт приложения обнуляет счётчики.

Интересно, можно ли как-то с этим бороться, чтобы при выводе графиков учитывалось то что счётчики не могут уменьшаться, а могут только увеличиваться и, соответственно, их уменьшение игнорировалось и они продолжали расти дальше.

 ,

KivApple
()

Lorify RIP?

Форум — Talks

https://chromewebstore.google.com/detail/lorify/lcbahplohbljaoccfaionnkdgakdfomn

This extension is no longer available because it doesn't follow best practices for Chrome extensions.

Собственно, мой хром самовольно отключил расширение после обновления и не даёт включить обратно.

 

KivApple
()

Проверка доступности сайта из России

Форум — Talks

Есть ли какой-то сервис проверки, что сайт не подпадает под блокировки РКН ПО ФАКТУ?

Допустим, я администратор сайта, сам по себе я в список блокировок не попадаю, ничего осуждаемого с точки зрения РФ не делаю, но всегда есть риски, что IP раньше принадлежал кому-то, кто не нравился РКН или что кто-то, кто не нравился РКН направил одну из своих DNS записей на этот IP.

В этом случае, соответственно, надо попросить хостера IP поменять, если важна доступность сайта из РФ.

Но для этого об этом надо узнать. А узнать это проблематично, если сам в РФ не находишься. VPN в Россию, как я понимаю, совсем не обязательно применяют блокировки, потому что в датацентрах своя атмосфера.

Проверка списков ничего не гарантирует, так как если в список не включён явно судом именно мой домен или мой IP, то результат будет отрицательный.

Нужен сервис, который делает curl с домашнего провайдера в РФ на заданный домен и говорит вернулась ли заглушка или нет. В идеале, если он работает с набором провайдеров.

 ,

KivApple
()

VPN в Docker сеть

Форум — Admin

Есть хост с кучей Docker контейнеров.

Хочу запустить ещё один контейнер, в котором будет VPN сервер, дающий доступ к одной из сетей Docker. Причём таким образом, чтобы клиенты VPN могли подключаться к контейнерам подключенным к этой сети, а контейнеры в этой сети могли подключаться к клиентам VPN.

В Интернет же ходить клиентам не надо через VPN.

Как это лучше организовать? Ни сервер, ни клиенты не в России, так что устойчивость к РКН не нужна. Зато нужна беспроблемная работа VPN на Mac OS.

 ,

KivApple
()

Целесообразность перехода на более жирный сервер со старым CPU

Форум — Admin

Сейчас мои петы крутятся на VPS 2 ядра 2 гига озу 20 гб ssd. Дёшево, но постоянно надо думать о свободной памяти и диске, всё оптимизировать и иногда случаются инциденты а-ля Docker сожрал диск.

Есть вариант доплатить некоторую приемлемую сумму и перейти на bare metal server с 4 ядрами 32 гб ОЗУ 2 х 1 тб ssd.

Но есть нюанс. На сервере будет стоять Intel Xeon E3 1220, который вышел в 2011 году (сейчас VPS работает на AMD EPYC 7282).

Собственно, вопрос, не огребу ли я из-за этого проблем?

Из нагрузки nginx со статикой, postgres, бекэнды на разных языках устроенные по принципу «сходить в базу и отдать клиенту, упаковав результат в JSON, проверив пару условий», prometheus и grafana для мониторинга всего этого хозяйства. Всё крутится в докер контейнерах.

В данный момент производительность по CPU меня удовлетворяет, старый CPU в бенчмарках всего на 20% слабее на ядро, зато у меня будет в два раза больше ядер. С другой стороны, он может не умеет какие-то важные новые инструкции, а ещё сильнее просаживаться на заплатках от spectre и meltdown (хотя, возможно, их можно отключить, так как сервер исполняет только тот код, который я сам на него принёс, а user generated у меня только неисполняемые данные).

Ещё надо учитывать, что dedicated bare metal он полностью мой, а vps я с кем-то делю.

 ,

KivApple
()

Docker сожрал диск

Форум — Admin

Собственно, сабж

root@maumyrtille:~# du -shc /var/lib/docker/*
116K	/var/lib/docker/buildkit
5.4G	/var/lib/docker/containers
4.0K	/var/lib/docker/engine-id
27M	/var/lib/docker/image
236K	/var/lib/docker/network
6.9G	/var/lib/docker/overlay2
469M	/var/lib/docker/plugins
4.0K	/var/lib/docker/runtimes
4.0K	/var/lib/docker/swarm
8.0K	/var/lib/docker/tmp
554M	/var/lib/docker/volumes
14G	total
root@maumyrtille:~# docker system df
TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          22        21        2.842GB   236.8MB (8%)
Containers      25        24        1.212MB   0B (0%)
Local Volumes   19        16        564.3MB   0B (0%)
Build Cache     0         0         0B        0B
root@maumyrtille:~# docker system prune
WARNING! This will remove:
  - all stopped containers
  - all networks not used by at least one container
  - all dangling images
  - unused build cache

Are you sure you want to continue? [y/N] y
Total reclaimed space: 0B

Чем занято более 10 ГБ?

 ,

KivApple
()

Что с Redis?

Форум — Development

Я тут узнал, что Redis с версии 7.4 сменил лицензию, вроде как нарушил обратную совместимость формата БД и по этому поводу случилась драма и наплодились его форки. Например, KeyDB, Valkey и т. д.

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

Собственно, вопрос к лоравцам: кто чем пользуется и на что стоит посмотреть?

Перемещено leave из talks

 ,

KivApple
()

Один Docker контейнер не может связаться с другим Docker контейнером

Форум — Admin

Имеется два docker compose файла.

infra/docker-compose.yaml:

services:
  watchtower:
    container_name: watchtower
    image: containrrr/watchtower
    restart: unless-stopped
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - $HOME/.docker/config.json:/config.json
    command: --label-enable
  prometheus:
    container_name: prometheus
    image: prom/prometheus
    user: root
    restart: unless-stopped
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - ./data/prometheus:/prometheus
    networks:
      - prometheus-network
networks:
  prometheus-network:
    driver: bridge

app/docker-compose.yaml:

services:
  backend:
    container_name: app-backend
    image: ...
    restart: unless-stopped
    environment:
      - DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}
    networks:
      - postgres-network
      - prometheus-network
    depends_on:
      - postgres
    labels:
      - "com.centurylinklabs.watchtower.enable=true"
  frontend:
    container_name: app-frontend
    ...
  postgres:
    container_name: app-postgres
    image: postgres:17-alpine
    ...
networks:
  postgres-network:
    driver: bridge
  prometheus-network:
    name: infra_prometheus-network
    external: true

Соответственно, запускается сначала infra, потом app.

Если зайти в контейнер app-backend и попробовать ping prometheus, то всё работает. Также можно попинговать самих себя - ping app-backend.

Если зайти в контейнер app-postgres и попробовать ping app-backend, то всё тоже работает.

Если зайти в контейнер prometheus и попробовать ping app-backend, то будет bad address 'app-backend'. Более того, если попробовать сделать ping prometheus, то эта команда тоже потерпит неудачу - то есть контейнер не видит сам себя.

Делаем docker inspect infra_prometheus-network:

[
    {
        "Name": "infra_prometheus-network",
        "Id": "ffec05671b873e60def53db831d4eb3966ba39bab74c01e8c7175362ae7da347",
        "Created": "2024-10-11T22:59:25.742311072Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.24.0.0/16",
                    "Gateway": "172.24.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": true,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "09bf47aa0f971ba2c9b686cb7bef947bd32eb7351ad41ec318118399345785d4": {
                "Name": "prometheus",
                "EndpointID": "dea3bb0a3e470cbcc9561ad8ef481c363f24a8c98628c4efd9d0193060092961",
                "MacAddress": "02:42:ac:18:00:02",
                "IPv4Address": "172.24.0.2/16",
                "IPv6Address": ""
            },
            "fa4dc2216105c90ccb1d165b6ce2b99dd43263a1bb459b43d0ce44a89330a9f8": {
                "Name": "app-backend",
                "EndpointID": "caa1b1371b290e7afd0273dd9a4e02781e2c895ed21d2913585739e233bc4784",
                "MacAddress": "02:42:ac:18:00:03",
                "IPv4Address": "172.24.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {
            "com.docker.compose.network": "prometheus-network",
            "com.docker.compose.project": "infra",
            "com.docker.compose.version": "2.29.7"
        }
    }
]

Видим, что IP контейнера app-backend - 172.24.0.3. Заходим в контейнер prometheus и делаем ping 172.24.0.3 - всё работает. То есть связь между контейнерами есть, но DNS не работает, причём только в одну сторону.

Пинговать внешние ресурсы типа Google из контейнера prometheus успешно получается, так что такой хотя бы DNS работает.

В чём может быть дело?

UPD: Проблема в официальном образе прометиуса - Один Docker контейнер не может связаться с другим Docker контейнером (комментарий), точнее скорее даже в базовом образе из которого он сделан. На неофициальном образе на базе alpine всё работает.

 ,

KivApple
()

Хранение в IndexedDB диапазона значений и выборка по одному значению

Форум — Development

Мне нужно сохранить в IndexedDB в Веб-приложении в браузере набор событий. Каждое событие характеризуется датой начала и датой конца.

Затем мне нужно выбирать события актуальные в заданный день (например, сегодня).

В SQL это выглядело бы как-то так:

SELECT * FROM events WHERE startDate >= $1 AND endDate <= $1

Но в IndexedDB нельзя делать запросы в такой свободной форме.

Есть две гипотетические возможности:

Создать композитный индекс и использовать его, но они очень плохо документированны и непонятно можно ли как-то сделать так, чтобы для startDate использовался IDBKeyRange.lowerBound, а для endDate использовался IDBKeyRange.upperBound в одном и том же запросе.

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

 indexeddb, ,

KivApple
()

Токены авторизации в веб-приложениях

Форум — Development

Вот чисто интуитивно есть два варианта реализации авторизации в веб-приложении:

1) Храним сессию в БД, юзеру выдаём после успешного ввода логина-пароля ключ (разумеется, ключ должен быть длинным и случайным, чтобы исключить угадывание). При каждом запросе вытаскиваем из БД сессию по ключу и проверяем, что сессия валидна.

2) Шифруем важные для нас данные об учётке и отдаем юзеру в качестве токена. При каждом запросе дешифруем токен и если получается осмысленный результат, то считаем юзера авторизованным, в БД не ходим. Так как ключ шифрования недоступен юзеру, то это тоже надёжно.

Второй вариант с точки зрения производительности выгоднее первого, так как мы уменьшаем I/O (плюс общую БД тяжелее масштабировать, чем инстансы приложения, так что жрать CPU лучше, чем жрать I/O).

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

Как это реализовано в первом варианте понятно - простое удаление сессии из БД. Как это реализовывать во втором варианте - непонятно.

Возникает вопрос, как устроены крупные сервисы типа всяких гуглов. Если посмотреть запросы, которые шлёт сайт гугла, там будут JWT токены, которые предполагают второй вариант (но, конечно, не гарантируют). Но у гугла есть опция, например, при смене пароля выбить все сессии во всех браузерах. Значит ли это, что гугл на каждый запрос к своему API дёргает БД сессий и JWT там только для красоты или каких-нибудь неважных сервисов.

В голову пришёл ещё компромиссный вариант, что можно гонять короткоживущие токены второго типа, но с расчётом, что они будут постоянно протухать и будет происходить переавторизация по токену первого типа. В этом случае получается, что функция «выйти со всех устройств» работать будет, но с лагом несколько минут/часов.

Интересно как это сделано в крупных сервисах. Используется ли вариант один, два или гибридный. Как во втором варианте работает функция выхода со всех устройств. Какой срок жизни токенов используется в третьем варианте обычно.

 

KivApple
()

SDL3 + Vulkan на Mac OS X

Форум — Development

Имеется Mac OS X, на которую установлен MoltenVk с помощью команды

brew install vulkan-tools

Этот пакет по зависимостям подтягивает и molten-vk, и vulkan-headers. Команда vulkaninfo успешно отрабатывает и показывает всякую информацию о Vulkan.

Затем, имеется простой код создающий окно в SDL (для простоты примера опущен код цикла событий, освобождения ресурсов и т. д.):

#include <stdio.h>
#include <SDL3/SDL.h>

int main(int argc, char *argv[]) {
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        printf("Unable to initialize SDL: %s", SDL_GetError());
        return 1;
    }
    SDL_Window *window = SDL_CreateWindow("My app", 800, 600, SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIGH_PIXEL_DENSITY | SDL_WINDOW_VULKAN);
    if (!window) {
        printf("Unable to create a window: %s", SDL_GetError());
        return 1;
    }
    return 0;
}

Код собирается следующим скриптом CMake:

cmake_minimum_required(VERSION 3.28)
project(MyApp)

set(BUILD_SHARED_LIBS OFF)

find_package(Vulkan REQUIRED)
add_subdirectory(lib/volk)
add_subdirectory(lib/SDL)

add_executable(MyApp main.c)
target_link_libraries(MyApp SDL3::SDL3-static volk::volk)

В данном случае lib/SDL это клонированный master https://github.com/libsdl-org/SDL, а lib/volk это клонированный master https://github.com/zeux/volk.

При запуске код выдаёт ошибку:

Unable to create a window: Failed to load Vulkan Portability library

В чём может быть проблема?

 ,

KivApple
()

Тип-обёртка для ошибок в Rust

Форум — Development

Допустим, я хочу сделать тип MyError, в который бы я мог упихать произвольную ошибку - хочу возвращать свой тип ошибки в Result методов моего трейта, чтобы абстрагироваться от деталей реализации. При этом я хочу, чтобы при написании реализации этих методов я мог использовать оператор вопроса с автоматическим преобразованием типа ошибки, а не вызывать вручную map_err.

use derive_more::Display;
use thiserror::Error;

#[derive(Error, Debug, Display)]
pub struct MyError(#[source] Box<dyn std::error::Error>);

impl<T: std::error::Error> From<T> for MyError {
	fn from(value: T) -> Self {
		Self(Box::new(value))
	}
}

Получаю ошибку компиляции:

error[E0119]: conflicting implementations of trait `From<MyError>` for type `MyError`
 --> src\mod.rs:9:1
  |
9 | impl<T: std::error::Error> From<T> for MyError {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: conflicting implementation in crate `core`:
          - impl<T> From<T> for T;

Как я понимаю, проблема в том, что MyError сам по себе реализует трейт Error и получается что-то вроде рекурсии.

Что с этим делать?

 

KivApple
()

Нарисовать граф

Форум — Development

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

Исходный датасет обрабатываю на Python, но в целом готов рассмотреть другие популярные языки.

Есть ли какие-то готовые библиотеки с таким функционалом? Graphwiz, как я понимаю, не умеет в тонкую кастомизацию внешнего вида связей.

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

Бонусом была бы возможность экспортировать граф не только в статичную картинку, но и в какую-нибудь HTML-страничку с возможностью зума, скроллинга и вывода дополнительной информации при наведении мыши на кружочки и связи.

 , ,

KivApple
()

Смешивание порошков

Форум — Science & Engineering

Допустим, есть два порошка двух разных веществ. Назовём их порошок А и порошок Б.

Требуется их смешать таким образом, чтобы в 10мл смеси было 1.5 г порошка А (а остальную массу составлял порошок Б).

С помощью каких технологий такое реализуется в домашних условиях? Допустим, есть точные весы, мерные баночки и керамическая кухонная ступка с пестиком.

Как я понимаю, главная засада в том, что смесь двух веществ будет иметь другую плотность нежели каждое вещество по отдельности (и при этом не как среднее плотностей ингридиентов с учётом пропорции смешивания). Так что, условно, 10 мл порошка А + 10 мл порошка Б дадут в сумме объём меньше 20 мл, поэтому нельзя решить задачу в лоб (вычислить плотности двух чистых веществ и найти пропорцию смешивания).

В голову приходит бинпоиск нужной пропорции, но это звучит замороченно (а ещё мы тратим порошки впустую) и интересно нет ли более аналитических решений.

 ,

KivApple
()

RSS подписка на новые темы