лысый

обновление по pritunl

VPN неожиданно сломался. Изучение показало, что не работает mongodb. Попытка переставить монгу ни к чему не привела — при запустке mongodb выдается Illegal instruction. На форумах пишут, что проблема в том, что начиная с 5-й версии (т.е. довольно давно) добавили поддержку AVX инструкций — https://inf.news/en/news/ce3a5224410b4f023f5d20fb9124e859.html. Почему у меня вдруг сломалось, хотя работало раньше — непонятно. Хостинг провайдер говорит, что ничего не менял, но вот факт — с августа работало, а потом раз и не больше не работает.

Интересно, что у x5x.ru есть опция предустановки pritunl. Но оказывается они ставят ее в докер, и там-то сборка конечно с ними совместимая. Поэтому подумав, я тоже пошел по этому пути — просто воспользоваться pritunl от хостинга.

Команды для настройки:

Получить пароль, чтобы зайти первый раз на веб-морду

docker exec -it pritunl sh -c "pritunl default-password"

Пробросить дополнительный порт к pritunl — это нужно потому что порт 443 я хочу использовать для openvpn — он как правило будет открыт, даже еcли другие порты местный админ или провайдер блокирует . Т.е. openvpn у меня работает через tcp/443, а вебморда pritunl — например через 5555.

Collapse )
лысый

установка Pritunl / OpenVPN

Переставил VPN на виртуальном сервере. Заметки по установке:

Я использую Pritunl с OpenVPN — возможно, есть что то лучше, но я привык. 

Памяти на сервере должно быть хотя бы 1Gb. На 512MB вроде бы сначала работает, но потом OOM-киллер убивает то mongodb, то pritunl

Операционку я выбрал debian. На сервере у меня всего 5Gb диска, убунта занимает сразу 4.5Gb а еще для pritunl и mongodb гигабайт нужен. Дебиан же после установки занимает около 2.5Gb.

Последовательность действий:

создать VDS (min 1Gb RAM / 5Gb SSD / Debian). Я использую https://x5x.host/?aff=4972 — сервер в США, 555р/мес

поставить sudo (apt get sudo)

добавить пользователя (adduser username), дать ему sudo права (usermod -aG sudo username), зайти этим юзером (ssh username@vds)

поставить mongodb — https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-debian/

поставить pritunl — https://docs.pritunl.com/docs/repo

включить сервисы — systemctl enable mongod, systemctl enable pritunl

диагностика проблем:

systemctl status

pritunl logs

зайти браузером на свой хост — в панель управления prinunl, действовать по инструкциям от pritunl

после начальной настройки pritunl в панели управления создать «организацию», создать «сервер», привязать сервер к организации, запустить сервер и можно создавать пользователей. Для каждого пользователя скачивается свой .ovpn файл, который отдается OpenVPN клиенту на телефоне или PC

Если нужно настроить VPN через squid — чтобы только браузер шел через VPN — в .ovpn файле пишется route-nopull, в браузере я использую расширение LightProxy для быстрого переключения.

squid ставится как обычно — apt install squid, так же управляется через systemctl. В /etc/squid/squid.conf для можно закомментировать все строчки «acl localnet src», кроме нужной локальной сети для VPN. И нужно раскомментировать строку «http_access allow localnet»

лысый

2048 on Rust/WinRT

Микрософт выкатила библиотеку для работы с Windows Runtime для Rust — Rust/WinRT. И, похоже, будет ее поддерживать. Сделана она так же, как и C++/WinRT — автоматически генерируемая библиотека для C++, скрывающая детали работы с COM, делает ее Kenny Kerr, автор C++/WinRT.

Так что я эту штуку стал смотреть и даже кое-что у меня на ней получилось: https://github.com/milyin/game2048-rs/

Чего пока не хватает — это поддержки xaml, т.е. всяких интерфейсных элементов, полей ввода, комбобоксов и прочего. По идее оно все есть в WinRT API, но примеров пока нет и понять, как это делать самому довольно сложно. Но, думаю, скоро и это будет.

лысый

GUI на Rust - есть прогресс

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

По сравнению с исходным вариантом переделано было почти все. Пришлось перейти на подсчет ссылок и динамический borrow checker — Rc<RefMut<Объект>>. От рассылки и обработки сообщений отказался. Теперь архитектура такая:
1. Виджеты собраны в дерево. Сообщения от ggez (нажатия кнопок, резайз окна, запрос на отрисовку и т.д.) пересылаются вниз по дереву.
2. Виждеты могут иметь обработчики событий. Обработчики вызываются не в момент обхода дерева (тогда бы были проблемы с borrow checker), а собираются в массив и вызываются после
3. Виджеты могут реализовывать интерфейсы. Например Checkbox реализует ICheckbox с методами get_state/set_state. А RadioGroup позволяет объединить в группу радиокнопок любые объекты, которые предоставляют ICheckbox. Аналогично будут сделаны методы типа enable/disable,  set_text/get_text и т.д.

Код выглядит вот так. borrow_mut() и clone() в глазах рябят конечно, но привыкнуть можно.


        let radio_a = CheckboxBuilder::new().build();
        let radio_b = CheckboxBuilder::new().build();
        let radio_c = CheckboxBuilder::new().build();

        let radio_group = RadioGroupBuilder::new()
            .add_widget(radio_a.clone())
            .add_widget(radio_b.clone())
            .add_widget(radio_c.clone())
            .build();

        let radio_ribbon = RibbonBuilder::new()
            .set_horizontal(true)
            .add_widget(radio_a)
            .add_widget(radio_b)
            .add_widget(radio_c)
            .build();

        let add_radio = {
            let radio_group = radio_group.clone();
            let radio_ribbon = radio_ribbon.clone();
            move |_| {
                let radio = CheckboxBuilder::new().build();
                radio_group.borrow_mut().add_widget(radio.clone());
                radio_ribbon.borrow_mut().add_widget(radio.clone());
            }
        };

        let remove_radio = {
            let radio_group = radio_group.clone();
            let radio_ribbon = radio_ribbon.clone();
            move |_| {
                let radio = radio_group.borrow().radios().last().map(|r| r.clone());
                if let Some(radio) = radio {
                    radio_group.borrow_mut().remove_widget(radio.clone());
                    radio_ribbon.borrow_mut().remove_widget(radio.clone());
                }
            }
        };

        let panel = PanelBuilder::new()
            .add_widget(
                RibbonBuilder::new()
                    .set_horizontal(false)
                    .add_widget(radio_ribbon.clone())
                    .add_widget(
                        RibbonBuilder::new()
                            .set_horizontal(true)
                            .add_widget(ButtonBuilder::new().on_click(add_radio).build())
                            .add_widget(ButtonBuilder::new().on_click(remove_radio).build())
                            .build(),
                    )
                    .build(),
            )
            .build();

        wm.add_window(panel, Rect::zero(), true);


Репозиторий - https://github.com/milyin/yorool_gui
лысый

GUI на Rust - мой подход к снаряду

Выложил прототип GUI на Rust'e. Назвал, разумееется, yorool_gui :-)

Пока умеет рисовать кнопки, нажимать кнопки и передавать сообщения между кнопками. Прототип рисует три кнопки и имитирует поведение radio buttons на них.

Сейчас популярный подход к GUI — делать в стиле Model-View-Controller. В такой архитектуре сделан Elm, на Расте сейчас развивается Azul. Оно конечно неплохо, но мне не нравится — я уже покусан MFC и хочу объекты с внутренним состоянием и чтобы между ними сообщения бегали.

Так что сейчас архитектура получилась такой:

  1. Виждет может владеть другими виджетами, так что получается дерево из них
  2. Все виждеты в дереве — это trait object типа Widget<MSG>
  3. MSG — это тип, из которого каждый виджет может извлечь сообщение, адресованное ему и завернуть в него свои сообщения
  4. MSG обрабатываются вот в таком примерно порядке:
    — собрать и обработать от всех виждетов сообщения (например о том, что у них что-то изменилось)
    —разослать им запросы на дополнительную информацию
    — собрать и обработать ответы и разослать команды на изменения

Для отрисовки и ввода я взял ggez — по прочтению вот этого обзора. Ну автор обзора (и он же основной автор ggez) предвзят наверное — но все нужное в ggez есть и пишется на нем легко.

лысый

Почему Visual Studio иногда постоянно перекомпилирует проект целиком

Vsiual Studio в очередной раз сошел с ума и начал все время считать, что проект был изменен и надо его целиком пересобрать, хотя ничего не менялось. На stack overflow есть советы, что с этим делать, но все не работающие. Ну например одна из возможных причин — в проект включен .h файл, которого нет на диске. Чтобы это выяснить надо всего то пройти по всему проекту и кликнуть в каждый .h файл. Ага, конечно. Во все 2000 файлов. Кликнуть.

Еще один совет — проверить, нет ли в проекте файла с датой большей текущей. Это проверить просто, но не помогло тоже.

Короче я с этим бился часа 4 наверное. До двух ночи. Не помогает ничего. И тут я подумал логически: когда эта хрень началась? А началась она после сегодняшней установки нового апдейта Windows — тут как раз что-то огромное приехало, долго очень обновляло. И вот я захожу в каталог виндовс и делаю в фаре поиск всех файлов и сортировку по дате. Бинго:

На часах 17 мая, 2 часа ночи (на тот момент, скриншот делал позже, когда пост писал). В каталоге Windows файлы с датой 17 мая, половина четвертого утра. Какого хрена? Гости из будущего, блин.

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


лысый

Странные грабли в C++

Наблюдал сейчас такое:

Файл a.cpp:

struct Foo {
 void foo() { cout << "A"; }
}

Файл b.cpp

struct Foo {
 void foo() { cout << "B\n"; }
}

void f() {
 Foo q;
 q.foo();
}

При вызове f() выдается "A". Какого хрена?

Прямо в таком виде пока не проверял, это наблюдается на более сложном коде. Но суть такова.

Update: спасибо http://motorist-nn.livejournal.com/ и https://ilya-314.livejournal.com/ — лечится анонимным namespace вокруг каждого Foo. Но все равно жопа — если про такое не знать, можно много огрести.

  • kofusun

Оппозиционная деятельность и рациональное мышление

Активные активисты своей жизнью демонстрируют "путь самурая" - одинокий воин против машины.
При всем уважении к ним, вся история показывает, что успех у самурая может состояться только при поддержке народа. Но народ не привлекается к оппозиционной деятельности.
Популярна теория "выученной беспомощности", которая психологическим языком объясняет это нежелание.
Однако надо понимать, что люди принимают рациональные решения, зачастую не осознавая в деталях механизма и оснований для принятия решений.
Попробуем проанализировать "выученную беспомощность" с точки зрения рационального мышления.
Для простоты понимания монетизируем выигрыши и проигрыши.
Предположим (сюжет типа Левиафана), субъект A обижен государством на сумму 1,000,000 руб. Субъект знает, что если он ввяжется в тяжбу, то он потратит 100 человекочасов. Заработок А - 200 руб. в час.
Вероятность победить государство (вернуть потерянное) очень мала, 0,1%. Но есть вероятность и огрести в тяжбе неприятностей, например, на сумму 200,000 с вероятностью повыше - 1%.
Итак:
возможный выигрыш - 1000 руб
возможный проигрыш- 2000 руб
альтернативный заработок - 20,000 руб.
Очевидно, что рациональным является плюнуть и пойти деньги зарабатывать.
Когда это не так?
- если нет альтернативного заработка (пенсионеры, безработные, студенты)
- если мышление нерационально (молодежь, фанатики) (узнаете?)
- если работают дополнительные факторы - чувство ответственности, справедливости, желание быть признанным или быть в группе (опять узнаете?)
- высокая стоимость потери либо ее высокая субъективная оценка
Но эти подходы могут привлечь только очень узкую часть населения.
Вариантами действий оппозиционных лидеров являются:
- пояснять, что потеря существенно выше (растет стоимость возможного выигрыша)
- существенно повышать вероятность выигрыша
- понижать риски при проигрыше
- показывать, что бездействие может повлиять на возможности альтернативного заработка.
Как это делать?
Один из вариантов, если не рассматривать изменение судебной системы и прилет инопланетян, это - ввязываться в проекты, в которых условия существенно более благоприятны, чем в рассмотренном примере. Поскольку гораздо рациональней портратить 100 человекочасов на проект с выигрышем в 100000 руб, чем с наиболее вероятным отрицательным выигрышем.
В том числе - делать проекты там, где есть дополнительные преимущества, например, в районах Москвы, где сформировался независимый депутатский корпус.
Да, так власть не поменять (хотя поменять), но будет создаваться история успеха, будут формироваться лучшие условия жизни для людей, будет демонстрация преимущества оппозиции перед ЕР. Альтернатива - сформировать имидж болтунов, которые пользы не приносят, а зарабатывают только шишки.
лысый

Rust и WebAssembly

Я тут неторопливо пилю веб сайт на Rust. Пока архитектура получается такая — сервер на Rust отдает и принимает Json, клиент на Elm рисует формочки и общается с сервером. Получается со стороны клиента тяжеловесно, мне не нравится. К тому же контролировать соответствие Json-а, который шлет / принимает клиент и текущего API сервера надо или вручную или какой-то генератор кода писать. 

Так что последнее время я все прикидывал, а нужно ли мне смотреть в сторону WebAssembly (в который Rust компилируется), а если нужно, то зачем?

И сегодня до индейца Джо дошло, что в сарае нет стены. Если мы можем строить из Rust-а код, исполняемый в браузере, а этот код может выставлять интерфейс в Js, то нам вообще не надо делать какое-то API сайта. Клиентское приложение на Js (хоть на Elm, хоть на б-гомерзких реактах с ангулярами) скачивает с сервера WebAssembly библиотеку, собранную из тех же исходников, что и сам сервер, а значит гарантированно совместимую с сервером по всем интерфейсам и структурам данных. Библиотека эта общается с сервером как захочет сама, скорее всего через web socket, бинарными данными. Любые изменения в протокол обмена можно вносить не трогая фронтенд. И вместо дрочения Json-а клиентское приложение просто вызывает обычные функции через js api.

Это, например, полностью решает проблему валидации данных — один и тот же код валидации, написанный на Rust, выполняется и на клиенте перед посылкой данных и на сервере при приеме данных.