Satont.
299 subscribers
321 photos
52 videos
1 file
201 links
Download Telegram
Можете отписываться кто подписан из-за стримов.
😭9🫡3😡3🖕21👌1🤡1
Постараюсь больше писать тогда о кодинге, хуле, раз такая пляска.
8
https://youtu.be/ufPGsZtqrac
https://blog.jetbrains.com/junie/2025/01/meet-junie-your-coding-agent-by-jetbrains/

Ну наконец они что-то сделали с ии.

Мне особо это не нужно, я попробовал cursor, windsurf — и они ну туповатые. Но так как ИИ технологии на хайпе, то это в любом случае идёт в плюс в копилку им.
Тем, кто держит свой сайт — рекомендую поставить его за Cloudflare, и озаботиться фильтрациями.

Сейчас всякие AI боты активно скрапят интернет, тем самым они могут создавать вам непредвиденную нагрузку.
Как от этого защититься:
- Паркуем домен на cloudflare.
- Во вкладке`DNS` указываем нужные нам записи A, AAAA, CNAME и так далее. Подробнее как это сделать — в интернете погуглите.
- После этого открываем вкладку Security -> Bots, и там включаем Block AI Bots, а так же Bot Fight Mode, если хотите всякие другие странные автоматические скраперы заблочить.

После этого на вкладке Security -> Events можете наблюдать (см. скриншот), как всякие Claude, GPT и т.д пытаются безуспешно считать ваш сайт.
Ну и всякие скрипты, ищущие уязвимости по типу /admin/login.php тоже отпадут.
👍161
А я для вас сегодня с приколами под го.

Знаете zod? Ну такая библеотечка с декларативным описанием схемы.

Есть отличная альтернатива под го: https://zog.dev/getting-started

Usage валидации очень прост:


import (
z "github.com/Oudwins/zog"
)


type User struct {
Name string `zog:"firstname"` // tag is optional. If not set zog will check for "name" field in the input data
Age int
}

var userSchema = z.Struct(z.Schema{
// its very important that schema keys like "name" match the struct field name NOT the input data
"name": z.String().Min(3, z.Message("Override default message")).Max(10),
"age": z.Int().GT(18).Required(z.Message("is required")),
})


func main() {
u := User{
Name: "Zog",
Age: 1,
}
errsMap := schema.Validate(&u)
if errsMap != nil {
// handle errors -> see Errors section
}
}


Или же err := userSchema.Parse(zhttp.Request(r), &user), что ещё больше сокращает, сначала спарсив реквест, потом прокинув в валидацию.

Посмотрите, поиграйтесь, это многим лучше go-validate, который очень пополярный и до жути не удобный.
🔥5
Я к вам с небольшим performance дайджестом по поводу Redis.

У меня на сервере Redis стабильно 100% потреблял, и вот что я понял:

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

Но знаете ли вы, что KEYS это антипаттерн? KEYS читает весь ваш кейспейс, то есть как я понимаю проверяет все ключи. Если у вас их сотни тысяч, миллионы = получаете выстрел в ногу по CPU нагрузке, так как это большая CPU bound таска.

Что же делать? — Использовать SCAN!

Со сканом всё хорошо, в голанге вы можете использовать конструкцию вида
iter := rdb.Scan(ctx, 0, "prefix:*", 0).Iterator()
for iter.Next(ctx) {
fmt.Println("keys", iter.Val())
}
if err := iter.Err(); err != nil {
panic(err)
}


И это будет работать хорошо. С малюсеньким НО — это плохо работает в dragonflydb (форк редиса), и скорее всего плохо работает во всех форках редиса.
Тут я конкретного решения подсказать не могу, но у себя я просто применил немного другой алгоритм: вместо скана всех ключей, я делаю strings.Fields(text) по входной строке, и по каждой части просто делаю redis.Exists команду, которая на порядок быстрее.

                       emotes := make(map[string]int)
splittedMsg := strings.Fields(msg.Message.Text)
for _, part := range splittedMsg {
// do not make redis requests if emote already present in map
if emote, ok := emotes[part]; ok {
emotes[part] = emote + 1
continue
}

if exists, _ := c.redis.Exists(
ctx,
fmt.Sprintf("emotes:channel:%s:%s", msg.BroadcasterUserId, part),
).Result(); exists == 1 {
emotes[part] += 1
continue
}

if exists, _ := c.redis.Exists(
ctx,
fmt.Sprintf("emotes:global:%s", part),
).Result(); exists == 1 {
emotes[part] += 1
continue
}
}


Да, такой workaround потенциально может породить 250 запросов к редису, потому как на твиче ограничение в 500 символов, и если написать сообщение по одной букве с пробелами, у нас получится 250 частей. Но это всё ещё лучше SCAN и уж тем более KEYS.

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

Так же рекоммендую вам использовать пайплайны на мутирующие операции, которые помогут вам избежать ненужных network-trip операций. То есть одним запросом вы можете сделать N SET, N EXPIRE и т.д операций.

А что скажите вы, есть ли у вас какие-то performance фишки?

P.S
Пришёл я к этому всему с помощью pprof гошки, проанализировав flame graph моего процесса. Не забывайте профилировать ваши приложения (по надобности).
👍101🥴1🦄1
Переписал Twir на Bun вместо Node

Bun это альтернативный js рантайм, который имеет кучу built-in апишек, написаных на языке zig. Апишки эти работают на порядок быстрее, чем в ноде, и их просто больше.
Для примера, из встроенного и написанного на zig есть:
- S3 client
- PostgreSQL client
- SQLite client
- zx альтернатива - $, чтобы удобнее было писать кроссплатформенные скриптики на js
- brypt/hash/argon2/sha/md
- Прикольный парсер семвера semver.satisfies("1.0.0", "^1.0.0");
- Парсеры цветов в hex, rgb, css, hsl
- Встроенный Glob, конечно же супер быстрый

Мне особенно подошло Single File Executable, когда вы можете скомпилить ваше приложение в бинарь вместе с рантаймом и зависимости. Я так деплою теперь свои приложения через докер, считай тоже самое, что Go.
Вот пример внимание, ПОЛНОГО докерфайла для bun бинаря:
FROM gcr.io/distroless/cc AS base  
COPY apps/eval/.out/twir-eval /app/twir-eval
ENV NODE_ENV=production
CMD ["/app/twir-eval"]

Да, тут я немного читерю, потому что установка зависимостей и собственно сборка бинарного файла у меня происходит в CI, но всё же.
Вот кстати команда для билда бинарного файла: bun build --compile --minify --sourcemap src/index.ts --outfile=.out/twir-eval

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

Теперь я не использую pre-транспайлинг кода вообще, то есть мне не нужен pre-build для например каких-то шейреных либ, ведь TypeScript код можно импортировать и запускать из коробки, имея адекватный watch. То есть я запускаю приложение, которые зависит от библеотечки, меняю код в библеоетчке - и приложение перезапускается само.
Фронтэнд бандлеры ведут себя идентичным образом, потому даже фронтэнд библеотеки мне не нужно прибилдить.

Я боялся, что у меня nuxt не заведётся, но... Знаете же, что nuxt под собой юзает nitro для большинства серверных магий? Так вот, у этого nitro есть поддержка bun прямо из коробки!
Просто воткнул в nuxt.config.ts данный конфиг и полетели!
nitro: {  
preset: 'bun'
}

Что с Vite, что с Nitro - никаких проблем не наблюдается.

bun --env-file=../../.env src/index.ts
Так же прикольно, что есть встроенный dotenv, но это уже мелочи. У ноды тоже уже есть вроде как.

В общем и целом мне зашло, продолжу использовать и ждать новых крутых фич.
А то всякие node медленно развиваются из-за того, что боятся ломать обратные совместимости. Тут такой проблемы нет, потому что не с чем совмещать. :)
Хотя они очень усиленно работают над совместимостью с нодой, у меня мои приложения завелись без изменений. GRPC, vm, knex, redis — работают.
👍9🔥31😎1
Satont. pinned «Переписал Twir на Bun вместо Node Bun это альтернативный js рантайм, который имеет кучу built-in апишек, написаных на языке zig. Апишки эти работают на порядок быстрее, чем в ноде, и их просто больше. Для примера, из встроенного и написанного на zig есть:…»
Планирую расширять ресурсы твира, и перекинуть всё на hetzner. Напоминаю, сейчас меня хостят бесплатно, один сервак всего. Докинуть ресурсов не могу. А ресурсы порой кончаются, например сейчас в пике может 12гб оперативки потребляться из 16ти. В какой-то скорый момент они кончатся.

Буду брать серваки на hetzner, горизонтальное масштабирование, в целом быстрее cpu, и вот это всё.
Буду признателен вам за подписки, или донаты копеечкой.
Если хотите чтобы я вас в ответ тоже отблагодарил, можете в лс писать. Могу предоставить vpn, какие-то фишки в твире, которые вы хотите (в силу возможностей). Жопу не покажу.

https://boosty.to/yakui
USDT TRC20: TVTagN51Wtykm8nXVthTJXStbNAAgYCmgp
USDC Polygon PoS: 0xbdde3a059458468371b613d113c15a97499950fb
Ethereum ERC20: 0xbdde3a059458468371b613d113c15a97499950fb
Bybit UID: 424720268
CARD RUB: 2202 2061 3958 1651
9👍1🔥1
Satont. pinned «Планирую расширять ресурсы твира, и перекинуть всё на hetzner. Напоминаю, сейчас меня хостят бесплатно, один сервак всего. Докинуть ресурсов не могу. А ресурсы порой кончаются, например сейчас в пике может 12гб оперативки потребляться из 16ти. В какой-то скорый…»
Satont.
Планирую расширять ресурсы твира, и перекинуть всё на hetzner. Напоминаю, сейчас меня хостят бесплатно, один сервак всего. Докинуть ресурсов не могу. А ресурсы порой кончаются, например сейчас в пике может 12гб оперативки потребляться из 16ти. В какой-то скорый…
Перенёс.

Взял 3 сервера, 2 под сервисы, 1 под бдшки, чтобы они отдельно крутились.

Процы на hetzner сразу видно лучше, вот avg load с сервера с базами: 0.09, 0.10, 0.09. Я так понимаю это потому что они быстрее и лучше справляются с поставленными вещами, плюсом не надо делить процессорное время уже с самими сервисами.

Поставил traefik, который за cloudflared тоннелем. Что это значит?
Вы запускаете агент cloudflared, создаёте докер сеть под него, и потом прикрепляете эту докер сеть к вашему сервису.
services:
cloudflared:
image: cloudflare/cloudflared
command: tunnel run
networks:
- cloudflared
environment:
- TUNNEL_TOKEN=${TUNNEL_TOKEN}


networks:
cloudflared:
external: true


И второй файлик:
services:
image: nginx
networks:
- cloudflared

networks:
cloudflared:
external: true


Запустили, и можно через панельку cloudflare открыть nginx по домену в сеть! (см. скриншот №1)

Там поддерживается как http, так и ssh, tcp. Можно почти любой сервис так открыть за доменом через эти тонели.

Ещё из апгрейда инфры я сделал zero-access до своих панелек. Например adminer закрыл, и логиниться могу только я туда. Не нужно настраивать traefik мидлвары, кастомные плагины, парится об env всяких. Просто настроил и работает. Можно даже сделать доступ за warp (впн клиент такой), если надо. Чем меньше env, тем лучше.

Брал кстати сервера в америке, и твич стал сильно быстрее отвечать за счёт этого. Но у этого минус есть - фронт у европейцев будет на 150мс медленее грузить.
🔥5👍3🏆1
Фига чё гитлаб придумали.

Если вы потеряли своё 2fa приложение, и у вас привязан ssh ключ — то вы можете перегенерить рекавери коды использовав ssh [email protected] 2fa_recovery_codes.
👍6🤯6
Ребят, если зарегаетесь по моей рефке на хетзнере — получите 20 евро на баланс клауда.
А когда потратите свои закинутые 10 евро — их получу я.
Потому, если кто задумывался и имеет возможность — дерзайте.

https://hetzner.cloud/?ref=CLdub3cH5y9p

П.С россияне не могут.
🗿8
Добавил в twir автоопределение играющей музыки на стриме, без необходимости подключать сторонний сервис по типу spotify, last.fm. Бот просто получает отрезочек стрима, отправляет его на определение.
Пока использую только shazam reverse-engineered api, потом подключу acrcloud, который уже будет платным для меня.
Но acrcloud имеет более лучшее определение, потому сделать придётся. Сейчас много мисов в определении, но уже хоть что-то, и бесплатно для меня и вас.
🔥15👍42🆒1
This media is not supported in your browser
VIEW IN TELEGRAM
🗿72💅2
Какой вариант вам нравится больше?
Думаю может взять старый дизайн, и осовременить его чутка, а конкретно взять блок features с нового.

👍https://twir.app
❤️https://web.archive.org/web/20230721100427/https://twir.app/
👍297
8
Может кому полезно будет: https://github.com/orval-labs/orval

Либа из openapi спеки генерит вам tanstack квери и мутации. Сам не пользовал, но выглядит интересно.
🔥6