mirror of
https://github.com/openlibrecommunity/olcrtc.git
synced 2026-05-26 07:08:11 +00:00
feat(mobile,client,mux): Android integration + SOCKS5 auth + reliability fixes
- mobile/: gomobile-bindable entry point for Android (combined libgojni.so) - internal/protect/: Android socket protect via VpnService for olcRTC sockets - internal/names/data/: embedded name pools for client identity generation - client: add SOCKS5 USER/PASS auth (RFC 1929) and bind to 127.0.0.1 - mux: infinite backpressure via waitForBufferSpace, raise buffer to 32MB, remove close-on-overflow (was corrupting reliable TCP streams over DC) - peer: remove 3-second drop in send worker — wait for SCTP buffer to drain instead of dropping packets (broke large HTTP/2 transfers like Instagram/X) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -87,7 +87,7 @@ func main() {
|
||||
case "srv":
|
||||
errCh <- server.Run(ctx, roomURL, keyHex, duo, dnsServer)
|
||||
case "cnc":
|
||||
errCh <- client.Run(ctx, roomURL, keyHex, socksPort, duo)
|
||||
errCh <- client.Run(ctx, roomURL, keyHex, socksPort, duo, "", "")
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ type Client struct {
|
||||
wg sync.WaitGroup
|
||||
}
|
||||
|
||||
func Run(ctx context.Context, roomURL, keyHex string, socksPort int, duo bool) error {
|
||||
func Run(ctx context.Context, roomURL, keyHex string, socksPort int, duo bool, socksUser, socksPass string) error {
|
||||
var key []byte
|
||||
var err error
|
||||
|
||||
@@ -150,7 +150,7 @@ func Run(ctx context.Context, roomURL, keyHex string, socksPort int, duo bool) e
|
||||
}
|
||||
log.Printf("Sent reset signal to server (clientID=%d)", c.clientID)
|
||||
|
||||
err = c.runSOCKS5(ctx, socksPort)
|
||||
err = c.runSOCKS5(ctx, socksPort, socksUser, socksPass)
|
||||
|
||||
log.Println("Waiting for client goroutines...")
|
||||
c.wg.Wait()
|
||||
@@ -170,13 +170,13 @@ func (c *Client) onData(data []byte) {
|
||||
c.mux.HandleFrame(plaintext)
|
||||
}
|
||||
|
||||
func (c *Client) runSOCKS5(ctx context.Context, port int) error {
|
||||
listener, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", port))
|
||||
func (c *Client) runSOCKS5(ctx context.Context, port int, username, password string) error {
|
||||
listener, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("SOCKS5 proxy listening on 0.0.0.0:%d", port)
|
||||
log.Printf("SOCKS5 proxy listening on 127.0.0.1:%d (auth=%v)", port, username != "")
|
||||
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
@@ -190,11 +190,11 @@ func (c *Client) runSOCKS5(ctx context.Context, port int) error {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
log.Println("SOCKS5 listener closed")
|
||||
|
||||
|
||||
for _, peer := range c.peers {
|
||||
peer.Close()
|
||||
}
|
||||
|
||||
|
||||
return nil
|
||||
default:
|
||||
log.Printf("Accept error: %v", err)
|
||||
@@ -202,15 +202,15 @@ func (c *Client) runSOCKS5(ctx context.Context, port int) error {
|
||||
}
|
||||
}
|
||||
|
||||
go c.handleSOCKS5(conn)
|
||||
go c.handleSOCKS5(conn, username, password)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) handleSOCKS5(conn net.Conn) {
|
||||
func (c *Client) handleSOCKS5(conn net.Conn, username, password string) {
|
||||
defer conn.Close()
|
||||
startTime := time.Now()
|
||||
|
||||
buf := make([]byte, 256)
|
||||
buf := make([]byte, 513)
|
||||
|
||||
if _, err := io.ReadFull(conn, buf[:2]); err != nil {
|
||||
return
|
||||
@@ -225,7 +225,48 @@ func (c *Client) handleSOCKS5(conn net.Conn) {
|
||||
return
|
||||
}
|
||||
|
||||
conn.Write([]byte{5, 0})
|
||||
requireAuth := username != ""
|
||||
wantMethod := byte(0x00)
|
||||
if requireAuth {
|
||||
wantMethod = 0x02
|
||||
}
|
||||
hasMethod := false
|
||||
for i := 0; i < int(nmethods); i++ {
|
||||
if buf[i] == wantMethod {
|
||||
hasMethod = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasMethod {
|
||||
conn.Write([]byte{5, 0xFF})
|
||||
return
|
||||
}
|
||||
conn.Write([]byte{5, wantMethod})
|
||||
|
||||
if requireAuth {
|
||||
// RFC 1929: VER ULEN UNAME PLEN PASSWD
|
||||
if _, err := io.ReadFull(conn, buf[:2]); err != nil {
|
||||
return
|
||||
}
|
||||
if buf[0] != 0x01 {
|
||||
return
|
||||
}
|
||||
ulen := int(buf[1])
|
||||
if _, err := io.ReadFull(conn, buf[:ulen+1]); err != nil {
|
||||
return
|
||||
}
|
||||
gotUser := string(buf[:ulen])
|
||||
plen := int(buf[ulen])
|
||||
if _, err := io.ReadFull(conn, buf[:plen]); err != nil {
|
||||
return
|
||||
}
|
||||
gotPass := string(buf[:plen])
|
||||
if gotUser != username || gotPass != password {
|
||||
conn.Write([]byte{0x01, 0x01})
|
||||
return
|
||||
}
|
||||
conn.Write([]byte{0x01, 0x00})
|
||||
}
|
||||
|
||||
if _, err := io.ReadFull(conn, buf[:4]); err != nil {
|
||||
return
|
||||
|
||||
@@ -7,18 +7,19 @@ package mux
|
||||
import (
|
||||
"encoding/binary"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/openlibrecommunity/olcrtc/internal/logger"
|
||||
)
|
||||
|
||||
type Stream struct {
|
||||
ID uint16
|
||||
ClientID uint32
|
||||
recvBuf []byte
|
||||
closed bool
|
||||
mu sync.Mutex
|
||||
nextSeq uint32
|
||||
outOfOrder map[uint32][]byte
|
||||
ID uint16
|
||||
ClientID uint32
|
||||
recvBuf []byte
|
||||
closed bool
|
||||
mu sync.Mutex
|
||||
nextSeq uint32
|
||||
outOfOrder map[uint32][]byte
|
||||
}
|
||||
|
||||
func (s *Stream) RecvBuf() []byte {
|
||||
@@ -48,7 +49,7 @@ func New(clientID uint32, onSend func([]byte) error) *Multiplexer {
|
||||
clientID: clientID,
|
||||
onSend: onSend,
|
||||
maxStreams: 10000,
|
||||
maxBufferSize: 1024 * 1024,
|
||||
maxBufferSize: 32 * 1024 * 1024,
|
||||
dataReady: make(map[uint16]chan struct{}),
|
||||
sendSeq: make(map[uint16]uint32),
|
||||
}
|
||||
@@ -220,26 +221,37 @@ func (m *Multiplexer) HandleFrame(frame []byte) {
|
||||
}
|
||||
|
||||
if seq == stream.nextSeq {
|
||||
if len(stream.recvBuf)+len(data) > m.maxBufferSize {
|
||||
stream.closed = true
|
||||
// Backpressure: if the stream buffer is full, release the mux lock and
|
||||
// wait for the reader to drain it. Dropping/closing here would corrupt
|
||||
// the TCP stream carried over the mux — large HTTP/2 downloads (X,
|
||||
// Instagram, YouTube) that push data faster than conn.Write can accept
|
||||
// would lose bytes and hang forever.
|
||||
if s := m.waitForBufferSpace(sid, clientID, len(data)); s == nil {
|
||||
return
|
||||
} else {
|
||||
stream = s
|
||||
}
|
||||
stream.recvBuf = append(stream.recvBuf, data...)
|
||||
stream.nextSeq++
|
||||
|
||||
|
||||
for {
|
||||
if nextData, ok := stream.outOfOrder[stream.nextSeq]; ok {
|
||||
if len(stream.recvBuf)+len(nextData) > m.maxBufferSize {
|
||||
stream.closed = true
|
||||
return
|
||||
}
|
||||
stream.recvBuf = append(stream.recvBuf, nextData...)
|
||||
delete(stream.outOfOrder, stream.nextSeq)
|
||||
stream.nextSeq++
|
||||
logger.Verbose("Applied out-of-order packet sid=%d seq=%d", sid, stream.nextSeq-1)
|
||||
} else {
|
||||
nextData, ok := stream.outOfOrder[stream.nextSeq]
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
if s := m.waitForBufferSpace(sid, clientID, len(nextData)); s == nil {
|
||||
return
|
||||
} else {
|
||||
stream = s
|
||||
}
|
||||
nextData, ok = stream.outOfOrder[stream.nextSeq]
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
stream.recvBuf = append(stream.recvBuf, nextData...)
|
||||
delete(stream.outOfOrder, stream.nextSeq)
|
||||
stream.nextSeq++
|
||||
logger.Verbose("Applied out-of-order packet sid=%d seq=%d", sid, stream.nextSeq-1)
|
||||
}
|
||||
|
||||
m.dataReadyMu.Lock()
|
||||
@@ -260,6 +272,25 @@ func (m *Multiplexer) HandleFrame(frame []byte) {
|
||||
}
|
||||
}
|
||||
|
||||
// waitForBufferSpace releases m.mu and waits until the stream's recvBuf has
|
||||
// room for `need` more bytes, then re-acquires the lock. Returns the (possibly
|
||||
// re-fetched) stream, or nil if the stream disappeared / was reset / closed.
|
||||
// Caller must hold m.mu (write-locked) on entry and will hold it on return.
|
||||
func (m *Multiplexer) waitForBufferSpace(sid uint16, clientID uint32, need int) *Stream {
|
||||
for {
|
||||
stream, ok := m.streams[sid]
|
||||
if !ok || stream.ClientID != clientID || stream.closed {
|
||||
return nil
|
||||
}
|
||||
if len(stream.recvBuf)+need <= m.maxBufferSize {
|
||||
return stream
|
||||
}
|
||||
m.mu.Unlock()
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
m.mu.Lock()
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Multiplexer) ReadStream(sid uint16) []byte {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
735
internal/names/data/names
Normal file
735
internal/names/data/names
Normal file
@@ -0,0 +1,735 @@
|
||||
Аарон
|
||||
Аба
|
||||
Аббас
|
||||
Абд аль-Узза
|
||||
Абдуллах
|
||||
Абид
|
||||
Аботур
|
||||
Аввакум
|
||||
Август
|
||||
Авдей
|
||||
Авель
|
||||
Аверкий
|
||||
Авигдор
|
||||
Авирмэд
|
||||
Авксентий
|
||||
Авл
|
||||
Авнер
|
||||
Аврелий
|
||||
Автандил
|
||||
Автоном
|
||||
Агапит
|
||||
Агафангел
|
||||
Агафодор
|
||||
Агафон
|
||||
Аги
|
||||
Агриппа
|
||||
Адам
|
||||
Адар
|
||||
Адиль
|
||||
Адольф
|
||||
Адонирам
|
||||
Адриан
|
||||
Азамат
|
||||
Азарий
|
||||
Азат
|
||||
Азиз
|
||||
Азим
|
||||
Айварс
|
||||
Айдар
|
||||
Айрат
|
||||
Акакий
|
||||
Аквилий
|
||||
Акиф
|
||||
Акоп
|
||||
Аксель
|
||||
Алан
|
||||
Аланус
|
||||
Алек
|
||||
Александр
|
||||
Алексей
|
||||
Алемдар
|
||||
Алик
|
||||
Алим
|
||||
Алипий
|
||||
Алишер
|
||||
Алмат
|
||||
Алоиз
|
||||
Алон
|
||||
Альберик
|
||||
Альберт
|
||||
Альбин
|
||||
Альваро
|
||||
Альвиан
|
||||
Альвизе
|
||||
Альфонс
|
||||
Альфред
|
||||
Амадис
|
||||
Амвросий
|
||||
Амедей
|
||||
Амин
|
||||
Амир
|
||||
Амр
|
||||
Амфилохий
|
||||
Анания
|
||||
Анас
|
||||
Анастасий
|
||||
Анатолий
|
||||
Ангеляр
|
||||
Андокид
|
||||
Андрей
|
||||
Андроник
|
||||
Аннерс
|
||||
Анри
|
||||
Ансельм
|
||||
Антипа
|
||||
Антон
|
||||
Антоний
|
||||
Антонин
|
||||
Антуан
|
||||
Арам
|
||||
Арефа
|
||||
Арзуман
|
||||
Аристарх
|
||||
Аристон
|
||||
Ариф
|
||||
Аркадий
|
||||
Арсений
|
||||
Артём
|
||||
Артур
|
||||
Арфаксад
|
||||
Асаф
|
||||
Атанасий
|
||||
Атом
|
||||
Аттик
|
||||
Афанасий
|
||||
Афинагор
|
||||
Афиней
|
||||
Афиф
|
||||
Африкан
|
||||
Ахилл
|
||||
Ахмад
|
||||
Ахтям
|
||||
Ашот
|
||||
Бадар
|
||||
Барни
|
||||
Бартоломео
|
||||
Басир
|
||||
Бахтияр
|
||||
Баян
|
||||
Безсон
|
||||
Бен
|
||||
Беньямин
|
||||
Берт
|
||||
Бехруз
|
||||
Билял
|
||||
Богдан
|
||||
Болеслав
|
||||
Бонавентура
|
||||
Борис
|
||||
Борислав
|
||||
Боян
|
||||
Бронислав
|
||||
Брячислав
|
||||
Бурхан
|
||||
Бутрос
|
||||
Бямбасурэн
|
||||
Вадим
|
||||
Валентин
|
||||
Валентино
|
||||
Валерий
|
||||
Валерьян
|
||||
Вальдемар
|
||||
Вангьял
|
||||
Варлам
|
||||
Варнава
|
||||
Варфоломей
|
||||
Василий
|
||||
Вахтанг
|
||||
Велвел
|
||||
Венансио
|
||||
Венедикт
|
||||
Вениамин
|
||||
Венцеслав
|
||||
Вигго
|
||||
Викентий
|
||||
Виктор
|
||||
Викторин
|
||||
Вильгельм
|
||||
Винцас
|
||||
Виссарион
|
||||
Виталий
|
||||
Витаутас
|
||||
Вито
|
||||
Владимир
|
||||
Владислав
|
||||
Владлен
|
||||
Влас
|
||||
Воислав
|
||||
Володарь
|
||||
Вольфганг
|
||||
Вописк
|
||||
Всеволод
|
||||
Всеслав
|
||||
Вук
|
||||
Вукол
|
||||
Вышеслав
|
||||
Вячеслав
|
||||
Габриеле
|
||||
Гавриил
|
||||
Гай
|
||||
Галактион
|
||||
Галымжан
|
||||
Гамлет
|
||||
Гаспар
|
||||
Гафур
|
||||
Гвидо
|
||||
Гейдар
|
||||
Геласий
|
||||
Гелий
|
||||
Гельмут
|
||||
Геннадий
|
||||
Генри
|
||||
Генрих
|
||||
Георге
|
||||
Георгий
|
||||
Гераклид
|
||||
Герасим
|
||||
Герберт
|
||||
Герман
|
||||
Германн
|
||||
Геронтий
|
||||
Герхард
|
||||
Гийом
|
||||
Гильем
|
||||
Гинкмар
|
||||
Глеб
|
||||
Гней
|
||||
Гоар
|
||||
Горацио
|
||||
Гордей
|
||||
Градислав
|
||||
Григорий
|
||||
Гримоальд
|
||||
Гуго
|
||||
Гурий
|
||||
Густав
|
||||
Гьялцен
|
||||
Давид
|
||||
Дамдинсурэн
|
||||
Дамир
|
||||
Даниил
|
||||
Дарий
|
||||
Демид
|
||||
Демьян
|
||||
Денеш
|
||||
Денис
|
||||
Децим
|
||||
Джаббар
|
||||
Джамиль
|
||||
Джан
|
||||
Джанер
|
||||
Джанфранко
|
||||
Джафар
|
||||
Джейкоб
|
||||
Джихангир
|
||||
Джованни
|
||||
Джон
|
||||
Джохар
|
||||
Джулиано
|
||||
Джулиус
|
||||
Дино
|
||||
Диодор
|
||||
Дитер
|
||||
Дитмар
|
||||
Дитрих
|
||||
Дмитрий
|
||||
Доминик
|
||||
Дональд
|
||||
Донат
|
||||
Дорофей
|
||||
Досифей
|
||||
Евгений
|
||||
Евграф
|
||||
Евдоким
|
||||
Еврит
|
||||
Евсей
|
||||
Евстафий
|
||||
Евтихан
|
||||
Евтихий
|
||||
Егор
|
||||
Елеазар
|
||||
Елисей
|
||||
Емельян
|
||||
Епифаний
|
||||
Ербол
|
||||
Ерванд
|
||||
Еремей
|
||||
Ермак
|
||||
Ермолай
|
||||
Ерофей
|
||||
Ефим
|
||||
Ефрем
|
||||
Жан
|
||||
Ждан
|
||||
Жером
|
||||
Жоан
|
||||
Захар
|
||||
Захария
|
||||
Збигнев
|
||||
Зденек
|
||||
Зейналабдин
|
||||
Зенон
|
||||
Зеэв
|
||||
Зигмунд
|
||||
Зинон
|
||||
Зия
|
||||
Золтан
|
||||
Зосима
|
||||
Иакинф
|
||||
Иан
|
||||
Ибрагим
|
||||
Ибрахим
|
||||
Иван
|
||||
Игнатий
|
||||
Игорь
|
||||
Иероним
|
||||
Иерофей
|
||||
Израиль
|
||||
Икрима
|
||||
Иларий
|
||||
Илия
|
||||
Илларион
|
||||
Илмари
|
||||
Ильфат
|
||||
Илья
|
||||
Имран
|
||||
Иннокентий
|
||||
Иоаким
|
||||
Иоанн
|
||||
Иоанникий
|
||||
Иоахим
|
||||
Иов
|
||||
Иоганн
|
||||
Иоганнес
|
||||
Ионафан
|
||||
Иосафат
|
||||
Ираклий
|
||||
Иржи
|
||||
Иринарх
|
||||
Ириней
|
||||
Иродион
|
||||
Иса
|
||||
Исаак
|
||||
Исаакий
|
||||
Исаия
|
||||
Исидор
|
||||
Ислам
|
||||
Исмаил
|
||||
Истислав
|
||||
Истома
|
||||
Истукарий
|
||||
Иштван
|
||||
Йюрген
|
||||
Кадваллон
|
||||
Кадир
|
||||
Казимир
|
||||
Каликст
|
||||
Калин
|
||||
Каллистрат
|
||||
Кальман
|
||||
Канат
|
||||
Карен
|
||||
Карлос
|
||||
Карп
|
||||
Картерий
|
||||
Кассиан
|
||||
Кассий
|
||||
Касторий
|
||||
Касьян
|
||||
Катберт
|
||||
Квинт
|
||||
Кехлер
|
||||
Киллиан
|
||||
Ким
|
||||
Кир
|
||||
Кириак
|
||||
Кирилл
|
||||
Клаас
|
||||
Клавдиан
|
||||
Клеоник
|
||||
Климент
|
||||
Кондрат
|
||||
Конон
|
||||
Конрад
|
||||
Константин
|
||||
Корнелиус
|
||||
Корнилий
|
||||
Коррадо
|
||||
Косьма
|
||||
Кратет
|
||||
Кратипп
|
||||
Крис
|
||||
Криспин
|
||||
Кристиан
|
||||
Кронид
|
||||
Кузьма
|
||||
Куприян
|
||||
Курбан
|
||||
Курт
|
||||
Кутлуг-Буга
|
||||
Кэлин
|
||||
Лаврентий
|
||||
Лавс
|
||||
Ладислав
|
||||
Лазарь
|
||||
Лайл
|
||||
Лампрехт
|
||||
Ландульф
|
||||
Лев
|
||||
Леви
|
||||
Ленни
|
||||
Леонид
|
||||
Леонтий
|
||||
Леонхард
|
||||
Лиам
|
||||
Линкей
|
||||
Логгин
|
||||
Лоренц
|
||||
Лоренцо
|
||||
Луи
|
||||
Луитпольд
|
||||
Лука
|
||||
Лукас
|
||||
Лукий
|
||||
Лукьян
|
||||
Луций
|
||||
Людовик
|
||||
Люцифер
|
||||
Макар
|
||||
Максим
|
||||
Максимиан
|
||||
Максимилиан
|
||||
Малик
|
||||
Малх
|
||||
Мамбет
|
||||
Маний
|
||||
Мануил
|
||||
Мануэль
|
||||
Мариан
|
||||
Мариус
|
||||
Марк
|
||||
Маркел
|
||||
Мартын
|
||||
Марчелло
|
||||
Матвей
|
||||
Матео
|
||||
Матиас
|
||||
Матфей
|
||||
Матфий
|
||||
Махмуд
|
||||
Меир
|
||||
Мелентий
|
||||
Мелитон
|
||||
Менахем-Мендель
|
||||
Месроп
|
||||
Мефодий
|
||||
Мечислав
|
||||
Мика
|
||||
Микеланджело
|
||||
Микулаш
|
||||
Милорад
|
||||
Мина
|
||||
Мирко
|
||||
Мирон
|
||||
Мирослав
|
||||
Митрофан
|
||||
Михаил
|
||||
Михей
|
||||
Младан
|
||||
Модест
|
||||
Моисей
|
||||
Мордехай
|
||||
Мстислав
|
||||
Мурад
|
||||
Мухаммед
|
||||
Мэдисон
|
||||
Мэлор
|
||||
Мэлс
|
||||
Назар
|
||||
Наиль
|
||||
Насиф
|
||||
Натан
|
||||
Натаниэль
|
||||
Наум
|
||||
Нафанаил
|
||||
Нацагдорж
|
||||
Нестор
|
||||
Никандр
|
||||
Никанор
|
||||
Никита
|
||||
Никифор
|
||||
Никодим
|
||||
Николай
|
||||
Нил
|
||||
Нильс
|
||||
Ноа
|
||||
Ной
|
||||
Норд
|
||||
Нуржан
|
||||
Нурлан
|
||||
Овадья
|
||||
Оге
|
||||
Одинец
|
||||
Октав
|
||||
Октавиан
|
||||
Октавий
|
||||
Октавио
|
||||
Олаф
|
||||
Оле
|
||||
Олег
|
||||
Оливер
|
||||
Ольгерд
|
||||
Онисим
|
||||
Орест
|
||||
Осип
|
||||
Оскар
|
||||
Осман
|
||||
Отто
|
||||
Оттон
|
||||
Очирбат
|
||||
Пабло
|
||||
Павел
|
||||
Павлин
|
||||
Павсикакий
|
||||
Паисий
|
||||
Палладий
|
||||
Панкратий
|
||||
Пантелеймон
|
||||
Папа
|
||||
Паруйр
|
||||
Парфений
|
||||
Патрик
|
||||
Пафнутий
|
||||
Пахомий
|
||||
Педро
|
||||
Пётр
|
||||
Пимен
|
||||
Пинхас
|
||||
Пипин
|
||||
Питирим
|
||||
Пол
|
||||
Полидор
|
||||
Полиевкт
|
||||
Поликарп
|
||||
Поликрат
|
||||
Порфирий
|
||||
Потап
|
||||
Предраг
|
||||
Премысл
|
||||
Приск
|
||||
Прокл
|
||||
Прокопий
|
||||
Прокул
|
||||
Протасий
|
||||
Прохор
|
||||
Публий
|
||||
Рагнар
|
||||
Рагуил
|
||||
Радмир
|
||||
Радослав
|
||||
Разумник
|
||||
Раймонд
|
||||
Рамадан
|
||||
Рамазан
|
||||
Рахман
|
||||
Рашад
|
||||
Рейнхард
|
||||
Ренат
|
||||
Реститут
|
||||
Ричард
|
||||
Роберт
|
||||
Родерик
|
||||
Родион
|
||||
Рожер
|
||||
Розарио
|
||||
Роман
|
||||
Ромен
|
||||
Рон
|
||||
Ронан
|
||||
Ростислав
|
||||
Рудольф
|
||||
Руслан
|
||||
Руф
|
||||
Руфин
|
||||
Рушан
|
||||
Сабит
|
||||
Савва
|
||||
Савватий
|
||||
Савелий
|
||||
Савин
|
||||
Саддам
|
||||
Садик
|
||||
Саид
|
||||
Салават
|
||||
Салих
|
||||
Саллюстий
|
||||
Салман
|
||||
Самуил
|
||||
Сармат
|
||||
Святослав
|
||||
Севастьян
|
||||
Северин
|
||||
Секст
|
||||
Секунд
|
||||
Семён
|
||||
Септимий
|
||||
Серапион
|
||||
Сергей
|
||||
Серж
|
||||
Сигеберт
|
||||
Сильвестр
|
||||
Симеон
|
||||
Симон
|
||||
Созон
|
||||
Соломон
|
||||
Сонам
|
||||
Софрон
|
||||
Спиридон
|
||||
Срджан
|
||||
Станислав
|
||||
Степан
|
||||
Стефано
|
||||
Стивен
|
||||
Таврион
|
||||
Тавус
|
||||
Тадеуш
|
||||
Тарас
|
||||
Тарасий
|
||||
Тейс
|
||||
Тендзин
|
||||
Теофил
|
||||
Терентий
|
||||
Терри
|
||||
Тиберий
|
||||
Тигран
|
||||
Тимофей
|
||||
Тимур
|
||||
Тихомир
|
||||
Тихон
|
||||
Томас
|
||||
Томоми
|
||||
Торос
|
||||
Тофик
|
||||
Трифон
|
||||
Трофим
|
||||
Тудхалия
|
||||
Тутмос
|
||||
Тьерри
|
||||
Тьяго
|
||||
Уве
|
||||
Уильям
|
||||
Улдис
|
||||
Ульрих
|
||||
Ульф
|
||||
Умар
|
||||
Урызмаг
|
||||
Усама
|
||||
Усман
|
||||
Фавст
|
||||
Фаддей
|
||||
Файзулла
|
||||
Фарид
|
||||
Фахраддин
|
||||
Федериго
|
||||
Федосей
|
||||
Федот
|
||||
Фейсал
|
||||
Феликс
|
||||
Феоктист
|
||||
Феофан
|
||||
Феофил
|
||||
Феофилакт
|
||||
Фердинанд
|
||||
Ференц
|
||||
Фёдор
|
||||
Фидель
|
||||
Филарет
|
||||
Филат
|
||||
Филип
|
||||
Филипп
|
||||
Философ
|
||||
Филострат
|
||||
Фирс
|
||||
Фока
|
||||
Фома
|
||||
Фотий
|
||||
Франц
|
||||
Франческо
|
||||
Фредерик
|
||||
Фридрих
|
||||
Фродо
|
||||
Фрол
|
||||
Фульк
|
||||
Хайме
|
||||
Ханс
|
||||
Харальд
|
||||
Харитон
|
||||
Харри
|
||||
Харрисон
|
||||
Хасан
|
||||
Хетаг
|
||||
Хильдерик
|
||||
Хирам
|
||||
Хлодвиг
|
||||
Хокон
|
||||
Хорив
|
||||
Хоселито
|
||||
Хосрой
|
||||
Хрисанф
|
||||
Христофор
|
||||
Хуан
|
||||
Цэрэндорж
|
||||
Чеслав
|
||||
Шалом
|
||||
Шамиль
|
||||
Шамсуддин
|
||||
Шапур
|
||||
Шарль
|
||||
Шейх-Хайдар
|
||||
Шон
|
||||
Эберхард
|
||||
Эдмунд
|
||||
Эдна
|
||||
Эдуард
|
||||
Элбэгдорж
|
||||
Элджернон
|
||||
Элиас
|
||||
Эллиот
|
||||
Эмиль
|
||||
Энрик
|
||||
Энрико
|
||||
Энтони
|
||||
Эразм
|
||||
Эраст
|
||||
Эрик
|
||||
Эрнст
|
||||
Эсекьель
|
||||
Эстебан
|
||||
Этьен
|
||||
Ювеналий
|
||||
Юлиан
|
||||
Юлий
|
||||
Юлиус
|
||||
Юрий
|
||||
Юстас
|
||||
Юстин
|
||||
Яков
|
||||
Якуб
|
||||
Якун
|
||||
Ян
|
||||
Яни
|
||||
Януарий
|
||||
Яромир
|
||||
Ярополк
|
||||
Ярослав
|
||||
735
internal/names/data/surnames
Normal file
735
internal/names/data/surnames
Normal file
@@ -0,0 +1,735 @@
|
||||
Аарон
|
||||
Аба
|
||||
Аббас
|
||||
Абд аль-Узза
|
||||
Абдуллах
|
||||
Абид
|
||||
Аботур
|
||||
Аввакум
|
||||
Август
|
||||
Авдей
|
||||
Авель
|
||||
Аверкий
|
||||
Авигдор
|
||||
Авирмэд
|
||||
Авксентий
|
||||
Авл
|
||||
Авнер
|
||||
Аврелий
|
||||
Автандил
|
||||
Автоном
|
||||
Агапит
|
||||
Агафангел
|
||||
Агафодор
|
||||
Агафон
|
||||
Аги
|
||||
Агриппа
|
||||
Адам
|
||||
Адар
|
||||
Адиль
|
||||
Адольф
|
||||
Адонирам
|
||||
Адриан
|
||||
Азамат
|
||||
Азарий
|
||||
Азат
|
||||
Азиз
|
||||
Азим
|
||||
Айварс
|
||||
Айдар
|
||||
Айрат
|
||||
Акакий
|
||||
Аквилий
|
||||
Акиф
|
||||
Акоп
|
||||
Аксель
|
||||
Алан
|
||||
Аланус
|
||||
Алек
|
||||
Александр
|
||||
Алексей
|
||||
Алемдар
|
||||
Алик
|
||||
Алим
|
||||
Алипий
|
||||
Алишер
|
||||
Алмат
|
||||
Алоиз
|
||||
Алон
|
||||
Альберик
|
||||
Альберт
|
||||
Альбин
|
||||
Альваро
|
||||
Альвиан
|
||||
Альвизе
|
||||
Альфонс
|
||||
Альфред
|
||||
Амадис
|
||||
Амвросий
|
||||
Амедей
|
||||
Амин
|
||||
Амир
|
||||
Амр
|
||||
Амфилохий
|
||||
Анания
|
||||
Анас
|
||||
Анастасий
|
||||
Анатолий
|
||||
Ангеляр
|
||||
Андокид
|
||||
Андрей
|
||||
Андроник
|
||||
Аннерс
|
||||
Анри
|
||||
Ансельм
|
||||
Антипа
|
||||
Антон
|
||||
Антоний
|
||||
Антонин
|
||||
Антуан
|
||||
Арам
|
||||
Арефа
|
||||
Арзуман
|
||||
Аристарх
|
||||
Аристон
|
||||
Ариф
|
||||
Аркадий
|
||||
Арсений
|
||||
Артём
|
||||
Артур
|
||||
Арфаксад
|
||||
Асаф
|
||||
Атанасий
|
||||
Атом
|
||||
Аттик
|
||||
Афанасий
|
||||
Афинагор
|
||||
Афиней
|
||||
Афиф
|
||||
Африкан
|
||||
Ахилл
|
||||
Ахмад
|
||||
Ахтям
|
||||
Ашот
|
||||
Бадар
|
||||
Барни
|
||||
Бартоломео
|
||||
Басир
|
||||
Бахтияр
|
||||
Баян
|
||||
Безсон
|
||||
Бен
|
||||
Беньямин
|
||||
Берт
|
||||
Бехруз
|
||||
Билял
|
||||
Богдан
|
||||
Болеслав
|
||||
Бонавентура
|
||||
Борис
|
||||
Борислав
|
||||
Боян
|
||||
Бронислав
|
||||
Брячислав
|
||||
Бурхан
|
||||
Бутрос
|
||||
Бямбасурэн
|
||||
Вадим
|
||||
Валентин
|
||||
Валентино
|
||||
Валерий
|
||||
Валерьян
|
||||
Вальдемар
|
||||
Вангьял
|
||||
Варлам
|
||||
Варнава
|
||||
Варфоломей
|
||||
Василий
|
||||
Вахтанг
|
||||
Велвел
|
||||
Венансио
|
||||
Венедикт
|
||||
Вениамин
|
||||
Венцеслав
|
||||
Вигго
|
||||
Викентий
|
||||
Виктор
|
||||
Викторин
|
||||
Вильгельм
|
||||
Винцас
|
||||
Виссарион
|
||||
Виталий
|
||||
Витаутас
|
||||
Вито
|
||||
Владимир
|
||||
Владислав
|
||||
Владлен
|
||||
Влас
|
||||
Воислав
|
||||
Володарь
|
||||
Вольфганг
|
||||
Вописк
|
||||
Всеволод
|
||||
Всеслав
|
||||
Вук
|
||||
Вукол
|
||||
Вышеслав
|
||||
Вячеслав
|
||||
Габриеле
|
||||
Гавриил
|
||||
Гай
|
||||
Галактион
|
||||
Галымжан
|
||||
Гамлет
|
||||
Гаспар
|
||||
Гафур
|
||||
Гвидо
|
||||
Гейдар
|
||||
Геласий
|
||||
Гелий
|
||||
Гельмут
|
||||
Геннадий
|
||||
Генри
|
||||
Генрих
|
||||
Георге
|
||||
Георгий
|
||||
Гераклид
|
||||
Герасим
|
||||
Герберт
|
||||
Герман
|
||||
Германн
|
||||
Геронтий
|
||||
Герхард
|
||||
Гийом
|
||||
Гильем
|
||||
Гинкмар
|
||||
Глеб
|
||||
Гней
|
||||
Гоар
|
||||
Горацио
|
||||
Гордей
|
||||
Градислав
|
||||
Григорий
|
||||
Гримоальд
|
||||
Гуго
|
||||
Гурий
|
||||
Густав
|
||||
Гьялцен
|
||||
Давид
|
||||
Дамдинсурэн
|
||||
Дамир
|
||||
Даниил
|
||||
Дарий
|
||||
Демид
|
||||
Демьян
|
||||
Денеш
|
||||
Денис
|
||||
Децим
|
||||
Джаббар
|
||||
Джамиль
|
||||
Джан
|
||||
Джанер
|
||||
Джанфранко
|
||||
Джафар
|
||||
Джейкоб
|
||||
Джихангир
|
||||
Джованни
|
||||
Джон
|
||||
Джохар
|
||||
Джулиано
|
||||
Джулиус
|
||||
Дино
|
||||
Диодор
|
||||
Дитер
|
||||
Дитмар
|
||||
Дитрих
|
||||
Дмитрий
|
||||
Доминик
|
||||
Дональд
|
||||
Донат
|
||||
Дорофей
|
||||
Досифей
|
||||
Евгений
|
||||
Евграф
|
||||
Евдоким
|
||||
Еврит
|
||||
Евсей
|
||||
Евстафий
|
||||
Евтихан
|
||||
Евтихий
|
||||
Егор
|
||||
Елеазар
|
||||
Елисей
|
||||
Емельян
|
||||
Епифаний
|
||||
Ербол
|
||||
Ерванд
|
||||
Еремей
|
||||
Ермак
|
||||
Ермолай
|
||||
Ерофей
|
||||
Ефим
|
||||
Ефрем
|
||||
Жан
|
||||
Ждан
|
||||
Жером
|
||||
Жоан
|
||||
Захар
|
||||
Захария
|
||||
Збигнев
|
||||
Зденек
|
||||
Зейналабдин
|
||||
Зенон
|
||||
Зеэв
|
||||
Зигмунд
|
||||
Зинон
|
||||
Зия
|
||||
Золтан
|
||||
Зосима
|
||||
Иакинф
|
||||
Иан
|
||||
Ибрагим
|
||||
Ибрахим
|
||||
Иван
|
||||
Игнатий
|
||||
Игорь
|
||||
Иероним
|
||||
Иерофей
|
||||
Израиль
|
||||
Икрима
|
||||
Иларий
|
||||
Илия
|
||||
Илларион
|
||||
Илмари
|
||||
Ильфат
|
||||
Илья
|
||||
Имран
|
||||
Иннокентий
|
||||
Иоаким
|
||||
Иоанн
|
||||
Иоанникий
|
||||
Иоахим
|
||||
Иов
|
||||
Иоганн
|
||||
Иоганнес
|
||||
Ионафан
|
||||
Иосафат
|
||||
Ираклий
|
||||
Иржи
|
||||
Иринарх
|
||||
Ириней
|
||||
Иродион
|
||||
Иса
|
||||
Исаак
|
||||
Исаакий
|
||||
Исаия
|
||||
Исидор
|
||||
Ислам
|
||||
Исмаил
|
||||
Истислав
|
||||
Истома
|
||||
Истукарий
|
||||
Иштван
|
||||
Йюрген
|
||||
Кадваллон
|
||||
Кадир
|
||||
Казимир
|
||||
Каликст
|
||||
Калин
|
||||
Каллистрат
|
||||
Кальман
|
||||
Канат
|
||||
Карен
|
||||
Карлос
|
||||
Карп
|
||||
Картерий
|
||||
Кассиан
|
||||
Кассий
|
||||
Касторий
|
||||
Касьян
|
||||
Катберт
|
||||
Квинт
|
||||
Кехлер
|
||||
Киллиан
|
||||
Ким
|
||||
Кир
|
||||
Кириак
|
||||
Кирилл
|
||||
Клаас
|
||||
Клавдиан
|
||||
Клеоник
|
||||
Климент
|
||||
Кондрат
|
||||
Конон
|
||||
Конрад
|
||||
Константин
|
||||
Корнелиус
|
||||
Корнилий
|
||||
Коррадо
|
||||
Косьма
|
||||
Кратет
|
||||
Кратипп
|
||||
Крис
|
||||
Криспин
|
||||
Кристиан
|
||||
Кронид
|
||||
Кузьма
|
||||
Куприян
|
||||
Курбан
|
||||
Курт
|
||||
Кутлуг-Буга
|
||||
Кэлин
|
||||
Лаврентий
|
||||
Лавс
|
||||
Ладислав
|
||||
Лазарь
|
||||
Лайл
|
||||
Лампрехт
|
||||
Ландульф
|
||||
Лев
|
||||
Леви
|
||||
Ленни
|
||||
Леонид
|
||||
Леонтий
|
||||
Леонхард
|
||||
Лиам
|
||||
Линкей
|
||||
Логгин
|
||||
Лоренц
|
||||
Лоренцо
|
||||
Луи
|
||||
Луитпольд
|
||||
Лука
|
||||
Лукас
|
||||
Лукий
|
||||
Лукьян
|
||||
Луций
|
||||
Людовик
|
||||
Люцифер
|
||||
Макар
|
||||
Максим
|
||||
Максимиан
|
||||
Максимилиан
|
||||
Малик
|
||||
Малх
|
||||
Мамбет
|
||||
Маний
|
||||
Мануил
|
||||
Мануэль
|
||||
Мариан
|
||||
Мариус
|
||||
Марк
|
||||
Маркел
|
||||
Мартын
|
||||
Марчелло
|
||||
Матвей
|
||||
Матео
|
||||
Матиас
|
||||
Матфей
|
||||
Матфий
|
||||
Махмуд
|
||||
Меир
|
||||
Мелентий
|
||||
Мелитон
|
||||
Менахем-Мендель
|
||||
Месроп
|
||||
Мефодий
|
||||
Мечислав
|
||||
Мика
|
||||
Микеланджело
|
||||
Микулаш
|
||||
Милорад
|
||||
Мина
|
||||
Мирко
|
||||
Мирон
|
||||
Мирослав
|
||||
Митрофан
|
||||
Михаил
|
||||
Михей
|
||||
Младан
|
||||
Модест
|
||||
Моисей
|
||||
Мордехай
|
||||
Мстислав
|
||||
Мурад
|
||||
Мухаммед
|
||||
Мэдисон
|
||||
Мэлор
|
||||
Мэлс
|
||||
Назар
|
||||
Наиль
|
||||
Насиф
|
||||
Натан
|
||||
Натаниэль
|
||||
Наум
|
||||
Нафанаил
|
||||
Нацагдорж
|
||||
Нестор
|
||||
Никандр
|
||||
Никанор
|
||||
Никита
|
||||
Никифор
|
||||
Никодим
|
||||
Николай
|
||||
Нил
|
||||
Нильс
|
||||
Ноа
|
||||
Ной
|
||||
Норд
|
||||
Нуржан
|
||||
Нурлан
|
||||
Овадья
|
||||
Оге
|
||||
Одинец
|
||||
Октав
|
||||
Октавиан
|
||||
Октавий
|
||||
Октавио
|
||||
Олаф
|
||||
Оле
|
||||
Олег
|
||||
Оливер
|
||||
Ольгерд
|
||||
Онисим
|
||||
Орест
|
||||
Осип
|
||||
Оскар
|
||||
Осман
|
||||
Отто
|
||||
Оттон
|
||||
Очирбат
|
||||
Пабло
|
||||
Павел
|
||||
Павлин
|
||||
Павсикакий
|
||||
Паисий
|
||||
Палладий
|
||||
Панкратий
|
||||
Пантелеймон
|
||||
Папа
|
||||
Паруйр
|
||||
Парфений
|
||||
Патрик
|
||||
Пафнутий
|
||||
Пахомий
|
||||
Педро
|
||||
Пётр
|
||||
Пимен
|
||||
Пинхас
|
||||
Пипин
|
||||
Питирим
|
||||
Пол
|
||||
Полидор
|
||||
Полиевкт
|
||||
Поликарп
|
||||
Поликрат
|
||||
Порфирий
|
||||
Потап
|
||||
Предраг
|
||||
Премысл
|
||||
Приск
|
||||
Прокл
|
||||
Прокопий
|
||||
Прокул
|
||||
Протасий
|
||||
Прохор
|
||||
Публий
|
||||
Рагнар
|
||||
Рагуил
|
||||
Радмир
|
||||
Радослав
|
||||
Разумник
|
||||
Раймонд
|
||||
Рамадан
|
||||
Рамазан
|
||||
Рахман
|
||||
Рашад
|
||||
Рейнхард
|
||||
Ренат
|
||||
Реститут
|
||||
Ричард
|
||||
Роберт
|
||||
Родерик
|
||||
Родион
|
||||
Рожер
|
||||
Розарио
|
||||
Роман
|
||||
Ромен
|
||||
Рон
|
||||
Ронан
|
||||
Ростислав
|
||||
Рудольф
|
||||
Руслан
|
||||
Руф
|
||||
Руфин
|
||||
Рушан
|
||||
Сабит
|
||||
Савва
|
||||
Савватий
|
||||
Савелий
|
||||
Савин
|
||||
Саддам
|
||||
Садик
|
||||
Саид
|
||||
Салават
|
||||
Салих
|
||||
Саллюстий
|
||||
Салман
|
||||
Самуил
|
||||
Сармат
|
||||
Святослав
|
||||
Севастьян
|
||||
Северин
|
||||
Секст
|
||||
Секунд
|
||||
Семён
|
||||
Септимий
|
||||
Серапион
|
||||
Сергей
|
||||
Серж
|
||||
Сигеберт
|
||||
Сильвестр
|
||||
Симеон
|
||||
Симон
|
||||
Созон
|
||||
Соломон
|
||||
Сонам
|
||||
Софрон
|
||||
Спиридон
|
||||
Срджан
|
||||
Станислав
|
||||
Степан
|
||||
Стефано
|
||||
Стивен
|
||||
Таврион
|
||||
Тавус
|
||||
Тадеуш
|
||||
Тарас
|
||||
Тарасий
|
||||
Тейс
|
||||
Тендзин
|
||||
Теофил
|
||||
Терентий
|
||||
Терри
|
||||
Тиберий
|
||||
Тигран
|
||||
Тимофей
|
||||
Тимур
|
||||
Тихомир
|
||||
Тихон
|
||||
Томас
|
||||
Томоми
|
||||
Торос
|
||||
Тофик
|
||||
Трифон
|
||||
Трофим
|
||||
Тудхалия
|
||||
Тутмос
|
||||
Тьерри
|
||||
Тьяго
|
||||
Уве
|
||||
Уильям
|
||||
Улдис
|
||||
Ульрих
|
||||
Ульф
|
||||
Умар
|
||||
Урызмаг
|
||||
Усама
|
||||
Усман
|
||||
Фавст
|
||||
Фаддей
|
||||
Файзулла
|
||||
Фарид
|
||||
Фахраддин
|
||||
Федериго
|
||||
Федосей
|
||||
Федот
|
||||
Фейсал
|
||||
Феликс
|
||||
Феоктист
|
||||
Феофан
|
||||
Феофил
|
||||
Феофилакт
|
||||
Фердинанд
|
||||
Ференц
|
||||
Фёдор
|
||||
Фидель
|
||||
Филарет
|
||||
Филат
|
||||
Филип
|
||||
Филипп
|
||||
Философ
|
||||
Филострат
|
||||
Фирс
|
||||
Фока
|
||||
Фома
|
||||
Фотий
|
||||
Франц
|
||||
Франческо
|
||||
Фредерик
|
||||
Фридрих
|
||||
Фродо
|
||||
Фрол
|
||||
Фульк
|
||||
Хайме
|
||||
Ханс
|
||||
Харальд
|
||||
Харитон
|
||||
Харри
|
||||
Харрисон
|
||||
Хасан
|
||||
Хетаг
|
||||
Хильдерик
|
||||
Хирам
|
||||
Хлодвиг
|
||||
Хокон
|
||||
Хорив
|
||||
Хоселито
|
||||
Хосрой
|
||||
Хрисанф
|
||||
Христофор
|
||||
Хуан
|
||||
Цэрэндорж
|
||||
Чеслав
|
||||
Шалом
|
||||
Шамиль
|
||||
Шамсуддин
|
||||
Шапур
|
||||
Шарль
|
||||
Шейх-Хайдар
|
||||
Шон
|
||||
Эберхард
|
||||
Эдмунд
|
||||
Эдна
|
||||
Эдуард
|
||||
Элбэгдорж
|
||||
Элджернон
|
||||
Элиас
|
||||
Эллиот
|
||||
Эмиль
|
||||
Энрик
|
||||
Энрико
|
||||
Энтони
|
||||
Эразм
|
||||
Эраст
|
||||
Эрик
|
||||
Эрнст
|
||||
Эсекьель
|
||||
Эстебан
|
||||
Этьен
|
||||
Ювеналий
|
||||
Юлиан
|
||||
Юлий
|
||||
Юлиус
|
||||
Юрий
|
||||
Юстас
|
||||
Юстин
|
||||
Яков
|
||||
Якуб
|
||||
Якун
|
||||
Ян
|
||||
Яни
|
||||
Януарий
|
||||
Яромир
|
||||
Ярополк
|
||||
Ярослав
|
||||
@@ -2,11 +2,18 @@ package names
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
_ "embed"
|
||||
"math/rand/v2"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//go:embed data/names
|
||||
var embeddedNames string
|
||||
|
||||
//go:embed data/surnames
|
||||
var embeddedSurnames string
|
||||
|
||||
var (
|
||||
firstNames []string
|
||||
lastNames []string
|
||||
@@ -24,6 +31,17 @@ var defaultLastNames = []string{
|
||||
"Орлов", "Андреев", "Макаров", "Никитин", "Захаров", "Зайцев", "Соловьёв", "Борисов", "Яковлев", "Григорьев",
|
||||
}
|
||||
|
||||
func parseEmbedded(raw string) []string {
|
||||
var names []string
|
||||
for _, line := range strings.Split(raw, "\n") {
|
||||
line = strings.TrimSpace(line)
|
||||
if line != "" {
|
||||
names = append(names, line)
|
||||
}
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
func loadNames(path string) ([]string, error) {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
@@ -43,10 +61,21 @@ func loadNames(path string) ([]string, error) {
|
||||
return names, scanner.Err()
|
||||
}
|
||||
|
||||
func LoadNameFiles(firstPath, lastPath string) error {
|
||||
firstNames = defaultFirstNames
|
||||
lastNames = defaultLastNames
|
||||
func init() {
|
||||
if names := parseEmbedded(embeddedNames); len(names) > 0 {
|
||||
firstNames = names
|
||||
} else {
|
||||
firstNames = defaultFirstNames
|
||||
}
|
||||
|
||||
if names := parseEmbedded(embeddedSurnames); len(names) > 0 {
|
||||
lastNames = names
|
||||
} else {
|
||||
lastNames = defaultLastNames
|
||||
}
|
||||
}
|
||||
|
||||
func LoadNameFiles(firstPath, lastPath string) error {
|
||||
if names, err := loadNames(firstPath); err == nil {
|
||||
firstNames = names
|
||||
}
|
||||
|
||||
66
internal/protect/protect.go
Normal file
66
internal/protect/protect.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package protect
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/http"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Protector is called with a socket file descriptor before connect.
|
||||
// On Android, this calls VpnService.protect(fd) to bypass VPN routing.
|
||||
var Protector func(fd int) bool
|
||||
|
||||
func controlFunc(network, address string, c syscall.RawConn) error {
|
||||
if Protector == nil {
|
||||
return nil
|
||||
}
|
||||
var err error
|
||||
c.Control(func(fd uintptr) {
|
||||
if !Protector(int(fd)) {
|
||||
err = &net.OpError{Op: "protect", Net: network, Err: net.ErrClosed}
|
||||
}
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// NewDialer returns a net.Dialer that calls Protector on each new socket.
|
||||
func NewDialer() *net.Dialer {
|
||||
return &net.Dialer{
|
||||
Timeout: 10 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
Control: controlFunc,
|
||||
}
|
||||
}
|
||||
|
||||
// NewHTTPClient returns an http.Client using protected sockets.
|
||||
func NewHTTPClient() *http.Client {
|
||||
dialer := NewDialer()
|
||||
transport := &http.Transport{
|
||||
DialContext: dialer.DialContext,
|
||||
ForceAttemptHTTP2: true,
|
||||
MaxIdleConns: 10,
|
||||
IdleConnTimeout: 30 * time.Second,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
ResponseHeaderTimeout: 10 * time.Second,
|
||||
}
|
||||
return &http.Client{Transport: transport}
|
||||
}
|
||||
|
||||
// DialContext dials using a protected socket.
|
||||
func DialContext(ctx context.Context, network, address string) (net.Conn, error) {
|
||||
return NewDialer().DialContext(ctx, network, address)
|
||||
}
|
||||
|
||||
// proxyDialer implements golang.org/x/net/proxy.Dialer for pion ICE.
|
||||
type proxyDialer struct{}
|
||||
|
||||
func (d *proxyDialer) Dial(network, addr string) (net.Conn, error) {
|
||||
return NewDialer().Dial(network, addr)
|
||||
}
|
||||
|
||||
// NewProxyDialer returns a proxy.Dialer that protects ICE sockets.
|
||||
func NewProxyDialer() *proxyDialer {
|
||||
return &proxyDialer{}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"net/url"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/openlibrecommunity/olcrtc/internal/protect"
|
||||
)
|
||||
|
||||
const apiBase = "https://cloud-api.yandex.ru/telemost_front/v2/telemost"
|
||||
@@ -44,7 +45,8 @@ func GetConnectionInfo(roomURL, displayName string) (*ConnectionInfo, error) {
|
||||
req.Header.Set("Origin", "https://telemost.yandex.ru")
|
||||
req.Header.Set("Referer", "https://telemost.yandex.ru/")
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
client := protect.NewHTTPClient()
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/google/uuid"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/openlibrecommunity/olcrtc/internal/logger"
|
||||
"github.com/openlibrecommunity/olcrtc/internal/protect"
|
||||
"github.com/pion/webrtc/v4"
|
||||
)
|
||||
|
||||
@@ -75,6 +76,9 @@ func (p *Peer) Connect(ctx context.Context) error {
|
||||
}
|
||||
|
||||
settingEngine := webrtc.SettingEngine{}
|
||||
if protect.Protector != nil {
|
||||
settingEngine.SetICEProxyDialer(protect.NewProxyDialer())
|
||||
}
|
||||
api := webrtc.NewAPI(webrtc.WithSettingEngine(settingEngine))
|
||||
|
||||
var err error
|
||||
@@ -169,7 +173,11 @@ func (p *Peer) Connect(ctx context.Context) error {
|
||||
})
|
||||
})
|
||||
|
||||
ws, _, err := websocket.DefaultDialer.Dial(p.conn.ClientConfig.MediaServerURL, nil)
|
||||
wsDialer := websocket.Dialer{
|
||||
NetDialContext: protect.DialContext,
|
||||
HandshakeTimeout: 15 * time.Second,
|
||||
}
|
||||
ws, _, err := wsDialer.Dial(p.conn.ClientConfig.MediaServerURL, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -723,31 +731,37 @@ func (p *Peer) processSendQueue(workerID int) {
|
||||
if p.dc == nil || p.dc.ReadyState() != webrtc.DataChannelStateOpen {
|
||||
continue
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
|
||||
|
||||
// Wait until SCTP buffer drains. Dropping here would corrupt the
|
||||
// carried TCP streams (the mux is a reliable transport) — large
|
||||
// downloads like Instagram/Twitter assets would hang forever
|
||||
// waiting for the missing bytes. Backpressure already propagates
|
||||
// upstream via CanSend() / the sendQueue length.
|
||||
waitStart := time.Now()
|
||||
for p.dc.BufferedAmount() > 64*1024 {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
if time.Since(start) > 3*time.Second {
|
||||
log.Printf("[WORKER-%d] Buffer wait timeout, dropping packet size=%d", workerID, len(data))
|
||||
if p.dc.ReadyState() != webrtc.DataChannelStateOpen {
|
||||
break
|
||||
}
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
|
||||
if time.Since(start) > 3*time.Second {
|
||||
if waited := time.Since(waitStart); waited > 500*time.Millisecond {
|
||||
logger.Verbose("[WORKER-%d] Buffer drained after %v", workerID, waited)
|
||||
}
|
||||
|
||||
if p.dc == nil || p.dc.ReadyState() != webrtc.DataChannelStateOpen {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
sendStart := time.Now()
|
||||
if err := p.dc.Send(data); err != nil {
|
||||
log.Printf("[WORKER-%d] Send error: %v", workerID, err)
|
||||
} else {
|
||||
elapsed := time.Since(sendStart)
|
||||
if elapsed > 50*time.Millisecond {
|
||||
log.Printf("[WORKER-%d] Sent %d bytes in %v (buffered: %d)",
|
||||
log.Printf("[WORKER-%d] Sent %d bytes in %v (buffered: %d)",
|
||||
workerID, len(data), elapsed, p.dc.BufferedAmount())
|
||||
} else {
|
||||
logger.Verbose("[WORKER-%d] Sent %d bytes (buffered: %d)",
|
||||
logger.Verbose("[WORKER-%d] Sent %d bytes (buffered: %d)",
|
||||
workerID, len(data), p.dc.BufferedAmount())
|
||||
}
|
||||
}
|
||||
|
||||
133
mobile/mobile.go
Normal file
133
mobile/mobile.go
Normal file
@@ -0,0 +1,133 @@
|
||||
// Package mobile provides a gomobile-compatible API for olcRTC.
|
||||
// Build with: gomobile bind -target=android ./mobile
|
||||
package mobile
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
"github.com/openlibrecommunity/olcrtc/internal/client"
|
||||
"github.com/openlibrecommunity/olcrtc/internal/logger"
|
||||
"github.com/openlibrecommunity/olcrtc/internal/protect"
|
||||
)
|
||||
|
||||
// SocketProtector protects sockets from VPN routing on Android.
|
||||
// Implement this interface in Kotlin/Java and pass to SetProtector.
|
||||
type SocketProtector interface {
|
||||
Protect(fd int) bool
|
||||
}
|
||||
|
||||
// LogWriter receives log messages from olcRTC.
|
||||
type LogWriter interface {
|
||||
WriteLog(msg string)
|
||||
}
|
||||
|
||||
var (
|
||||
mu sync.Mutex
|
||||
cancel context.CancelFunc
|
||||
done chan error
|
||||
)
|
||||
|
||||
// SetProtector sets the Android VPN socket protector.
|
||||
// Must be called before Start.
|
||||
func SetProtector(p SocketProtector) {
|
||||
if p == nil {
|
||||
protect.Protector = nil
|
||||
return
|
||||
}
|
||||
protect.Protector = func(fd int) bool {
|
||||
return p.Protect(fd)
|
||||
}
|
||||
}
|
||||
|
||||
// SetLogWriter sets a custom log writer for olcRTC output.
|
||||
func SetLogWriter(w LogWriter) {
|
||||
if w != nil {
|
||||
log.SetOutput(&logBridge{w: w})
|
||||
}
|
||||
}
|
||||
|
||||
// SetDebug enables or disables verbose logging.
|
||||
func SetDebug(enabled bool) {
|
||||
logger.SetVerbose(enabled)
|
||||
if enabled {
|
||||
log.SetFlags(log.Ltime | log.Lshortfile)
|
||||
} else {
|
||||
log.SetFlags(log.Ltime)
|
||||
}
|
||||
}
|
||||
|
||||
// Start launches the olcRTC client in background.
|
||||
// roomID: Telemost room ID (e.g. "xxx-xxx-xxx")
|
||||
// keyHex: 64-char hex encryption key
|
||||
// socksPort: local SOCKS5 proxy port (e.g. 10808)
|
||||
// duo: use dual channels for higher throughput
|
||||
// socksUser/socksPass: SOCKS5 credentials (empty = no auth)
|
||||
func Start(roomID, keyHex string, socksPort int, duo bool, socksUser, socksPass string) error {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
if cancel != nil {
|
||||
return fmt.Errorf("olcRTC already running")
|
||||
}
|
||||
|
||||
if roomID == "" {
|
||||
return fmt.Errorf("roomID is required")
|
||||
}
|
||||
if keyHex == "" {
|
||||
return fmt.Errorf("keyHex is required")
|
||||
}
|
||||
|
||||
roomURL := "https://telemost.yandex.ru/j/" + roomID
|
||||
|
||||
ctx, c := context.WithCancel(context.Background())
|
||||
cancel = c
|
||||
done = make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
err := client.Run(ctx, roomURL, keyHex, socksPort, duo, socksUser, socksPass)
|
||||
mu.Lock()
|
||||
cancel = nil
|
||||
mu.Unlock()
|
||||
done <- err
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop gracefully stops the olcRTC client.
|
||||
func Stop() {
|
||||
mu.Lock()
|
||||
c := cancel
|
||||
d := done
|
||||
mu.Unlock()
|
||||
|
||||
if c == nil {
|
||||
return
|
||||
}
|
||||
|
||||
c()
|
||||
|
||||
if d != nil {
|
||||
<-d
|
||||
}
|
||||
}
|
||||
|
||||
// IsRunning returns true if the olcRTC client is active.
|
||||
func IsRunning() bool {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
return cancel != nil
|
||||
}
|
||||
|
||||
// logBridge adapts LogWriter to io.Writer for log package.
|
||||
type logBridge struct {
|
||||
w LogWriter
|
||||
}
|
||||
|
||||
func (b *logBridge) Write(p []byte) (n int, err error) {
|
||||
b.w.WriteLog(string(p))
|
||||
return len(p), nil
|
||||
}
|
||||
Reference in New Issue
Block a user