𝐈𝐍 𝐆𝐎𝐃 𝐖𝐄 𝐓𝐑𝐔𝐒𝐓 🕋
We comply with Telegram's guidelines:
- No financial advice or scams
- Ethical and legal content only
- Respectful community
Join us for market updates, airdrops, and crypto education!
Last updated 1 day, 2 hours ago
[ We are not the first, we try to be the best ]
Last updated 2 months, 2 weeks ago
FAST MTPROTO PROXIES FOR TELEGRAM
Ads : @IR_proxi_sale
Last updated 1 month, 4 weeks ago
برنامهنویسهای ادایی: قهرمانان سلفیگیر! ?
برنامهنویسهای ادایی، آن دسته از افراد در دنیای فناوری هستند که بیشتر از اینکه به کدنویسی بپردازند، به گرفتن سلفیهای خفن با لپتاپ و قهوهشان مشغولاند. بیایید نگاهی به دنیای رنگارنگ آنها بندازیم!
سلفیهای جذاب با لپتاپ
اولین نشانهی برنامهنویس ادایی، سلفیهای بینظیرش است. این افراد بهطور مداوم در حال گرفتن عکس از خود در کنار لپتاپ و کتابهای مهندسی نرمافزار هستند. شاید فکر کنید که آنها در حال کدنویسی هستند، اما واقعیت این است که در حال تنظیم نور و زاویه دوربین برای گرفتن عکس بعدیشان هستند!
"نگاه کن من دارم کد میزنم"
در واقع، آنها فقط در حال چک کردن فید اینستاگرامشان هستند!
بحث درباره clean architecture همه جا!
همیشه همراه خود کتاب های برنامه نویسی خفن را حمل میکنند حتی در کافه و مهمانی ها!
تا بحث درباره برنامه نویسی شود، کتاب های که درباره clean architecture و ddd و ... خوانده اند صحبت میکنند اما هنوز نمیتوانند یک پروژه todo را با ساختار مناسب پیاده سازی کنند!
میز کار به سبک هنری ?
میز کار این برنامهنویسها مثل یک گالری هنری است؛ قهوهساز، کتابهای مهندسی نرمافزار، و چندین ماگ با نوشتههای خندهدار. آنها با افتخار به شما نشان میدهند که "این کتاب رو تازه خریدم!" در حالی که هیچوقت حتی یک صفحه از آن را نخواندهاند. گویی که داشتن کتابهای مهندسی نرمافزار بهعنوان یک اکسسوری مهم است!
پوششهای خاص با تیشرتهای برنامهنویسی ?
این افراد معمولاً تیشرتهای با طرحهای مرتبط با برنامهنویسی میپوشند، مثل "Code is my cardio" یا "I'm silently correcting your code". گویی لباسشان بهترین بیانیهی حرفهای آنهاست!
رویدادهای کافهای ☕️
برنامهنویسهای ادایی معمولاً در کافهها جمع میشوند تا نمیدونم واقعا چیکار کنن ☹️
بحثهای پرشور درباره buzzword ها
وقتی دو برنامهنویس ادایی با هم ملاقات میکنند، یک بحث پرشور درباره جدیدترین فریمورکها یا زبانهای برنامهنویسی شروع میشود. در واقع، این بحثها بیشتر شبیه به مسابقهی خودستایی است تا تبادل دانش واقعی!
اوه از همه بدتر وقتی با یه برنامه نویس ادایی صحبت میکنید کلمات و اصطلاحاتی رو بکار میبره که خداهم تاحالا نشنیده!
بازورد چیه؟ #buzzword
مبادا مثل آدم کد بزنی!
کد های یک برنامه نویس ادایی رو فقط یک برنامه نویس ادایی دیگه میفهمه!
تا جای ممکن سعی میکنن کدی بنویسن که پیچیده و غیرقابل فهم باشه.
چیزی که فکر میکنن:
پشمام چه کدی زدی?
ولی واقعیت موضوع:
این چه کدشریه دیگه?
نحوه احراز هویت با OAuth
OAuth
یک پروتکل احراز هویت و مجوز است که به کاربران اجازه میدهد بدون نیاز به اشتراکگذاری اطلاعات ورود خود، به وبسایتها و اپلیکیشنهای مختلف دسترسی پیدا کنند. این پروتکل معمولاً در سه مرحله اصلی کار میکند:
- یک پروژه جدید ایجاد کنید.
- OAuth 2.0 client ID ایجاد کنید.
- URL کال بک (Redirect URI) را مشخص کنید.
پس از این مراحل، یک Client ID
و Client Secret
دریافت خواهید کرد.
2. درخواست مجوز
هنگامی که کاربر روی دکمه "ورود با گوگل" کلیک میکند، شما باید او را به URL زیر هدایت کنید:
https://accounts.google.com/o/oauth2/v2/auth?client\_id=YOUR\_CLIENT\_ID&redirect\_uri=YOUR\_REDIRECT\_URI&response\_type=code&scope=email%20profile
در اینجا:
- YOUR_CLIENT_ID
: شناسه کلاینت شما
- YOUR_REDIRECT_URI
: URL کال بک شما
- scope
: اطلاعاتی که میخواهید از کاربر بگیرید (مثل ایمیل و پروفایل)
3. دریافت کد تأیید
پس از اینکه کاربر مجوز را تأیید کرد، گوگل کاربر را به URL کال بک شما باز میگرداند و یک پارامتر code
به همراه خواهد داشت.
4. تبادل کد برای توکن دسترسی
شما باید یک درخواست POST به URL زیر ارسال کنید تا کد را برای توکن دسترسی مبادله کنید:
POST https://oauth2.googleapis.com/token
بدنه درخواست باید شامل موارد زیر باشد:
{
"code": "CODE\_RECEIVED\_FROM\_GOOGLE",
"client\_id": "YOUR\_CLIENT\_ID",
"client\_secret": "YOUR\_CLIENT\_SECRET",
"redirect\_uri": "YOUR\_REDIRECT\_URI",
"grant\_type": "authorization\_code"
}
5. دریافت توکن دسترسی
اگر درخواست موفق باشد، شما یک پاسخ JSON دریافت میکنید که شامل access_token
و اطلاعات دیگر است.
6. احراز هویت و دسترسی به اطلاعات کاربر
با استفاده از access\_token
، میتوانید اطلاعات کاربر را از API گوگل دریافت کنید. برای مثال:
GET https://www.googleapis.com/oauth2/v2/userinfo
Authorization: Bearer ACCESS\_TOKEN
7. وریفای توکن
برای اطمینان از صحت توکن، میتوانید توکن را به یکی از انتهای API گوگل ارسال کنید تا اطلاعات مربوط به توکن و اعتبار آن را دریافت کنید.
چند نکته درباره وب سوکت و توضیح ساده برای درک بهتر
فرآیند ارتباط وبسوکت
شروع با HTTP/HTTPS:
- کلاینت ابتدا یک درخواست HTTP به سرور میفرستد. این درخواست شامل هدرهای خاصی است که نشاندهنده تمایل به ارتقاء ارتباط به وبسوکت است. این هدرها شامل موارد زیر هستند:
- Upgrade: websocket
- Connection: Upgrade
ارتقاء به وبسوکت:
- سرور درخواست را دریافت کرده و بررسی میکند. اگر شرایط درست باشد، با یک پاسخ خاص به کلاینت، ارتباط را به وبسوکت ارتقاء میدهد. این پاسخ شامل وضعیت 101 Switching Protocols است.
استفاده از ws:// و wss://:
- پس از ارتقاء، ارتباط بهصورت دائمی و دوطرفه برقرار میشود.
- ws://
نشاندهنده استفاده از پروتکل وبسوکت بر روی HTTP است.
- wss://
نشاندهنده استفاده از پروتکل وبسوکت بر روی HTTPS است (که رمزنگاری شده است).
چرا ws:// استفاده میشود؟
- ws://localhost:8080
- این URL نشان میدهد که ارتباط نهایی بهصورت وبسوکت انجام میشود.
نکته:
در HTTP/2، مکانیزم آپگرید به وبسوکت از طریق هدرهای HTTP/1.1 استفاده نمیشود. HTTP/2 به صورت ذاتی از این روش پشتیبانی نمیکند. برای ارتباط وبسوکت در HTTP/2، معمولاً از HTTP/1.1 برای ایجاد و ارتقاء ارتباط استفاده میشود یا از روشهای دیگری برای مدیریت ارتباطات بلادرنگ بهره میگیرند.
روشهای دیگه برای مدیریت ارتباطات بلادرنگ:
1. Server-Sent Events (SSE):
- یک ارتباط یکطرفه است که سرور میتواند بهطور پیوسته دادهها را به کلاینت ارسال کند.
- مناسب برای برنامههایی که نیاز به ارسال دادههای بلادرنگ از سرور به کلاینت دارند.
Long Polling:
- کلاینت یک درخواست HTTP ارسال میکند و سرور تا زمانی که دادهای برای ارسال وجود ندارد، پاسخ را معلق نگه میدارد(یک تایم اوت مشخص هم دارد مثلا 20 ثانیه)
- پس از ارسال داده، کلاینت بلافاصله یک درخواست جدید ارسال میکند.
HTTP/2 Streams:
- استفاده از قابلیت چندپخشی و استریمهای همزمان در HTTP/2 برای ارسال و دریافت دادههای بلادرنگ.
gRPC:
- یک فریمورک RPC بر پایه HTTP/2 که از ارتباطات بلادرنگ و استریمینگ پشتیبانی میکند.
چرا نیاز به درخواست HTTP اولیه است؟
وبسوکتها بهعنوان یک پروتکل ارتقاء بر روی HTTP طراحی شدهاند تا با زیرساختهای موجود وب سازگار باشند. این امر به کلاینتها و سرورها اجازه میدهد تا از همان پورتها و مکانیزمهای امنیتی استفاده کنند.
مثال در گولنگ:
```
package main
import (
"fmt"
"net/http"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
// checking conditions
return true
},
}
func handleConnections(w http.ResponseWriter, r *http.Request) {
// upgrade http request to websocket
ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
fmt.Println(err)
return
}
defer ws.Close()
// messages
for {
messageType, msg, err := ws.ReadMessage()
if err != nil {
fmt.Println(err)
break
}
fmt.Printf("Received: %s\n", msg)
err = ws.WriteMessage(messageType, msg)
if err != nil {
fmt.Println(err)
break
}
}
}
func main() {
http.HandleFunc("/", handleConnections)
fmt.Println("Server started on :8080")
err := http.ListenAndServe(":8080", nil)
if err != nil {
fmt.Println("Error starting server:", err)
}
}
```
تو چند دقیقه نحوه کار با Redis Pub/Sub رو تو پایتون یاد بگیر
Pub/Sub
(انتشار/اشتراک) یک الگوی معماری است که به برنامهها اجازه میدهد تا به صورت غیرمستقیم با یکدیگر ارتباط برقرار کنند. در این الگو، تولیدکنندگان اطلاعات (Publisher) پیامها را منتشر میکنند و مصرفکنندگان (Subscriber) به موضوعات (Topics) خاصی که به آنها علاقهمند هستند، اشتراک میگذارند. این سیستم اجازه میدهد تا بدون نیاز به وابستگی مستقیم با یکدیگر، اطلاعات را تبادل کنند.
مزایای Pub/Sub
- کاهش وابستگیها: تولیدکنندگان و مصرفکنندگان نیازی به شناخت یکدیگر ندارند.
- مقیاسپذیری: میتوان به سادگی مصرفکنندگان و تولیدکنندگان جدیدی اضافه کرد.
- توزیعپذیری: میتوان سیستمها را به صورت توزیعشده پیادهسازی کرد.
مثال ساده با Redis Pub/Sub
در این مثال، از Redis به عنوان سیستم Pub/Sub استفاده خواهیم کرد. ابتدا باید Redis را نصب و راهاندازی کنید.
نصب Redis
تو ریپازیتوری ای که لینکشو آخر پست میذارم، سرویس ردیس رو توی docker-compose.yml مشخص کردم و روی داکر اجراش میکنیم.
همچنین داخل فایل .env تنظیمات ردیس رو میتونید مشخص کنید.
docker\-compose up \-d
پیادهسازی در پایتون
برای این کار به کتابخانه redis
نیاز داریم. میتوانید آن را با pip نصب کنید:
pip install redis
در این مثال، یک Publisher و یک Subscriber خواهیم داشت.
Publisher (server.py):
```
import json
from redis import StrictRedis
server = StrictRedis(host="localhost", port=6399, password="redis_password", db=0)
# redis ping
print(server.ping())
topic = "example_topic"
data = {
"name": "alireza",
"age": 22,
}
server.publish(channel=topic, message=json.dumps(data))
```
در قدم اول کانکشن با ردیس رو می سازیم.
با متد ping میتونیم چک کنیم وضعیت کانگشنمون اوکی هست یا نه(جنبه آموزشی نوشتمش)
بعد مشخص کردیم که topic ما اسمش چیه.
دیتایی که قراره داخل payload مسیج قرار بدیم رو مشخص کردیم که بصورت دیکشنری هستش و بعدش اومدیم به json تبدیلش کردیم و مسیح رو پابلیش کردیم.
Subscriber (client.py):
```
import json
from redis import StrictRedis
client = StrictRedis(host="localhost", port=6399, password="redis_password", db=0)
topic = "example_topic"
pubsub = client.pubsub()
pubsub.subscribe(topic)
print("waiting for message...")
while True:
for message in pubsub.listen():
if message["data"] == 1:
continue
match message["type"]:
case topic:
# TODO - change serialization. json is not good
data = json.loads(message["data"])
print("received message", data["name"], data["age"])
```
در قدم اول یک کانکشن ردیس گرفتیم. بعد تاپیکی که subscribe میکنیمش رو مشخص کردیم(میتونیم چندین تا تاپیک رو سابسکرایب کنیم)
در قدم بعدی داخل یک long running میایم به مسیج های جدیدی که میاد گوش میدیم و یک switch case زدیم و براساس تاپیک ها میتونیم کارهای خاص خودش رو انجام بدیم.
نحوه اجرا
client.py
را اجرا کنید سورس کد:
https://github.com/alireza-fa/redis-pub-sub-example
پروتکل بافر (Protocol Buffers)
پروتکل بافر یک روش سریالیزیشن دادهها است که به شما اجازه میدهد دادهها را به صورت ساختاریافته و بهینه ذخیره و منتقل کنید. این روش بهویژه در سیستمهای توزیعشده و میکروسرویسها کاربرد فراوانی دارد.
مزایای پروتکل بافر:
- فشردهسازی: دادهها به صورت باینری ذخیره میشوند، که باعث کاهش حجم میشود.
- قابلیت توسعه: میتوانید به سادگی فیلدهای جدید به پیامها اضافه کنید.
- پشتیبانی از چندین زبان: از زبانهای مختلفی پشتیبانی میکند و میتوانید کد های زبان های مختلفی رو با کامپایر پروتکل بافر ایجاد کنید.
از پروتکل بافر می توانیم در هسته سیستم خودمون، تو شرایط مختلفی که نیاز به سریالیزیشن و انتقال دیتا داریم، استفاده کنیم حتی اگر grpc هم استفاده نکنیم.
مثال: استفاده از پروتکل بافر در یک سیستم Message Driven
بیایید یک سناریو فرضی بسازیم که در آن از پروتکل بافر برای سریالیزیشن پیامها در یک سیستم مبتنی بر پیام استفاده میکنیم. ما یک سرویس داریم که دادههای کاربر را دریافت میکند و آنها را به یک صف پیام ارسال میکند.
۱. تعریف پیامها
ابتدا ساختار پیامها را در یک فایل .proto
تعریف میکنیم:
```
syntax = "proto3";
package user;
message User {
string name = 1;
int32 age = 2;
}
```
۲. تولید کد گولنگ
برای تولید کد گولنگ، ابتدا باید ابزار protoc
و پلاگین Go را نصب کنید:
go get google.golang.org/protobuf/cmd/protoc\-gen\-go
سپس، کد گولنگ را با دستور زیر تولید کنید:
protoc \-\-go\_out=. user.proto
۳. ارسال پیام به سیستم Message Driven
حالا بیایید یک تولیدکننده پیام ایجاد کنیم که یک کاربر را سریالیزه کرده و به یک صف پیام (مثل Kafka) ارسال کند.
```
package main
import (
"log"
"github.com/confluentinc/confluent-kafka-go/kafka"
"google.golang.org/protobuf/proto"
"your_project/user"
)
func main() {
producer, err := kafka.NewProducer(&kafka.ConfigMap{"bootstrap.servers": "localhost:9092"})
if err != nil {
log.Fatal(err)
}
defer producer.Close()
// create user
user := &user.User{
Name: "Alice",
Age: 30,
}
// serialize data
data, err := proto.Marshal(user)
if err != nil {
log.Fatal("Failed to serialize user:", err)
}
// publish a message
topic := "users"
err = producer.Produce(&kafka.Message{
TopicPartition: kafka.TopicPartition{Topic: &topic, Partition: kafka.PartitionAny},
Value: data,
}, nil)
if err != nil {
log.Fatal("Failed to send message:", err)
}
producer.Flush(15 * 1000)
log.Println("User sent to Kafka:", user.Name)
}
```
۴. کانسیوم پیام از سیستم Message Driven
حالا بیایید یک consumer پیام بسازیم که پیامهای دریافتی را دیسریالیزه کند:
```
package main
import (
"log"
"github.com/confluentinc/confluent-kafka-go/kafka"
"google.golang.org/protobuf/proto"
"your_project/user"
)
func main() {
consumer, err := kafka.NewConsumer(&kafka.ConfigMap{
"bootstrap.servers": "localhost:9092",
"group.id": "user_group",
"auto.offset.reset": "earliest",
})
if err != nil {
log.Fatal(err)
}
defer consumer.Close()
consumer.SubscribeTopics([]string{"users"}, nil)
for {
msg, err := consumer.ReadMessage(-1)
if err != nil {
log.Println("Error reading message:", err)
continue
}
// deserialization
receivedUser := &user.User{}
if err := proto.Unmarshal(msg.Value, receivedUser); err != nil {
log.Println("Failed to unmarshal user:", err)
continue
}
// use info
log.Printf("Received User: Name: %s, Age: %d\n", receivedUser.Name, receivedUser.Age)
}
}
```
pkg.go.dev
protoc-gen-go command - google.golang.org/protobuf/cmd/protoc-gen-go - Go Packages
The protoc-gen-go binary is a protoc plugin to generate Go code for both proto2 and proto3 versions of the protocol buffer language.
از پایتون 3.13 چخبر؟ ?
1. یک مفسر تعاملی (Interactive Interpreter) بهتر
پایتون 3.13 بهبودهای قابل توجهی در مفسر تعاملی به همراه پیامهای خطای پیشرفته معرفی میکند. مفسر تعاملی جدید اکنون از رنگبندی پشتیبانی میکند و تجربهای بصریتر ارائه میدهد. این پشتیبانی از رنگ به tracebacks و خروجی doctest نیز گسترش مییابد. کاربران میتوانند رنگبندی را از طریق متغیرهای محیطی PYTHON_COLORS و NO_COLOR غیرفعال کنند.
علاوه بر این، پایتون 3.12 شامل یک کامپایلر JIT (Just-In-Time) اولیه بر اساس PEP 744 است. اگرچه در حال حاضر بهطور پیشفرض غیرفعال است، این کامپایلر نشاندهنده بهبودهای عملکردی امیدوارکنندهای است و برنامههایی برای بهبودهای بیشتر در نسخههای بعدی وجود دارد.
2. کامپایل آزمایشی Just-in-Time (JIT)
پایتون یک کامپایلر آزمایشی just-in-time (JIT) معرفی میکند که در صورت فعالسازی، میتواند برخی برنامههای پایتون را سریعتر کند. کامپایلر JIT با ترجمه bytecode تخصصی Tier 1 به یک نمایش میانی داخلی Tier 2 جدید کار میکند که برای ترجمه به کد ماشین بهینه شده است. چندین مرحله بهینهسازی به Tier 2 IR اعمال میشود قبل از اینکه تفسیر یا به کد ماشین ترجمه شود. گزینههای پیکربندی (–enable-experimental-jit) به کاربران اجازه میدهد تا رفتار JIT را در زمان ساخت و اجرا کنترل کنند، از جمله فعال یا غیرفعال کردن JIT و مفسر Tier
مزایای بالقوه کامپایلر JIT:
بهبود عملکرد قابل توجه برای بخشهای خاصی از کد که از اجرای کد ماشین سود میبرند.
امکان بهینهسازیهای آینده که قبلاً با تفسیر bytecode ممکن نبودند.
3. سی پایتون (CPython) آزمایشی بدون GIL
سی پایتون اکنون از اجرای بدون Global Interpreter Lock (GIL) پشتیبانی میکند، که امکان اجرای multithreadding آزاد را با پیکربندی –disable-gil فراهم میسازد. اجرای چندریسمانی آزاد به بهرهبرداری بهتر از هستههای CPU موجود از طریق اجرای موازی ریسمانها کمک میکند و به برنامههایی که برای threading طراحی شدهاند، سود میرساند.
ماژولهای توسعه C-API باید بهطور خاص برای ساختار چندریسمانی آزاد ساخته شوند و باید با استفاده از مکانیزمهای مناسب، پشتیبانی از اجرای بدون GIL را نشان دهند.
4. گزارشدهی و راهنمایی خطای بهبود یافته
ردیابی خطا در پایتون در نسخه جدید بهبود یافته است. مفسر اکنون پیامهای خطا را بهطور پیشفرض هنگام نمایش tracebacks رنگی میکند. در ویژگی دیگر، پیام خطا در صورت ارسال یک کلیدواژه اشتباه به یک تابع، کلیدواژه صحیح را پیشنهاد میدهد.
گاهی اوقات که یک اسکریپت همنام یک ماژول کتابخانه استاندارد است، پایتون اکنون پیام خطای دقیقی ارائه میدهد و پیشنهاد میکند برای درک بهتر، نام ماژول تغییر کند.
```
sys.version_info
Traceback (most recent call last):
File "", line 1, in
NameError: name 'sys' is not defined. Did you forget to import 'sys'!
```
5. جمعآوری زباله افزایشی
پایتون 3.12 جمعآوری زباله افزایشی را معرفی میکند که زمان توقف حداکثر را برای هیپهای بزرگتر به طور قابل توجهی کاهش میدهد. این بهبود بهویژه برای برنامههایی با تخصیص و آزادسازی حافظه زیاد مفید است.
\# Python 3.12
import gc
gc.isincremental() \# Returns True
این ویژگی به برنامههای پایتون اجازه میدهد تا روانتر اجرا شوند و تأثیر توقفهای جمعآوری زباله کاهش یابد، که به بهبود عملکرد کلی و واکنشپذیری منجر میشود.
6. بهینهسازی حافظه برای Docstrings
پایتون 3.13 تغییری ظریف اما مؤثر برای بهبود کارایی حافظه معرفی میکند: بهینهسازی حافظه برای Docstrings. این ویژگی منبع پنهانی از استفاده حافظه و اندازه فایل مرتبط با docstrings در کد پایتون را هدف قرار میدهد.
محدودیتهای Docstrings سنتی در پایتون به شرح زیر است:
بهطور سنتی، docstrings در پایتون شامل هر گونه فاصله تورفتگی ابتدایی بودند. در حالی که این فضاهای اضافی به نظر بیضرر میآیند، به اندازه کلی فایلهای bytecode کامپایلشده (.pyc) افزوده و احتمالاً استفاده از حافظه را هنگام اجرای کد افزایش میدادند.
مزایای بهینهسازی حافظه برای Docstrings:
بهینهسازی حافظه برای Docstrings این ناکارآمدی را برطرف میکند. بهطور خودکار هر گونه تورفتگی ابتدایی را از docstrings قبل از فرآیند کامپایل حذف میکند.
این اطمینان میدهد که تنها محتوای واقعی docstring ذخیره میشود، که منجر به:
کاهش استفاده از حافظه برای فایلهای bytecode کامپایلشده.
احتمالاً کاهش استفاده از حافظه در هنگام اجرای برنامه، بهویژه برای پروژههایی با docstring گسترده.
این کتابه نکات و روش های خوبی رو تو جنگو گفته که خوندنش واقعا دید خوبی بهتون میده.
#موقت
پستای آخر چقدر بوسم میکنید خبریه؟
𝐈𝐍 𝐆𝐎𝐃 𝐖𝐄 𝐓𝐑𝐔𝐒𝐓 🕋
We comply with Telegram's guidelines:
- No financial advice or scams
- Ethical and legal content only
- Respectful community
Join us for market updates, airdrops, and crypto education!
Last updated 1 day, 2 hours ago
[ We are not the first, we try to be the best ]
Last updated 2 months, 2 weeks ago
FAST MTPROTO PROXIES FOR TELEGRAM
Ads : @IR_proxi_sale
Last updated 1 month, 4 weeks ago