هذه واجهة برمجة تطبيقات منخفضة المستوى مخصصة لمؤلفي المكتبات وحالات الاستخدام المتقدمة.
بدء خادم (Bun.listen())
لبدء خادم TCP مع Bun.listen:
Bun.listen({
hostname: "localhost",
port: 8080,
socket: {
data(socket, data) {}, // رسالة مستلمة من العميل
open(socket) {}, // تم فتح المقبس
close(socket, error) {}, // تم إغلاق المقبس
drain(socket) {}, // المقبس جاهز لمزيد من البيانات
error(socket, error) {}, // معالج الأخطاء
},
});واجهة برمجة تطبيقات مصممة للسرعة
في Bun، يتم الإعلان عن مجموعة من المعالجات مرة واحدة لكل خادم بدلاً من تعيين استدعاءات لكل مقبس، كما في Node.js EventEmitters أو واجهة برمجة التطبيقات القياسية للويب WebSocket.
Bun.listen({
hostname: "localhost",
port: 8080,
socket: {
open(socket) {},
data(socket, data) {},
drain(socket) {},
close(socket, error) {},
error(socket, error) {},
},
});بالنسبة للخوادم الحساسة للأداء، يمكن أن يتسبب تعيين مستمعين لكل مقبس في ضغط كبير على جامع القمامة ويزيد من استخدام الذاكرة. على النقيض من ذلك، يخصص Bun دالة معالج واحدة فقط لكل حدث ويشاركها بين جميع المقابس. هذا تحسين صغير، لكنه يتراكم.
يمكن إرفاق بيانات سياقية بمقبس في معالج open.
type SocketData = { sessionId: string };
Bun.listen<SocketData>({
hostname: "localhost",
port: 8080,
socket: {
data(socket, data) {
socket.write(`${socket.data.sessionId}: ack`);
},
open(socket) {
socket.data = { sessionId: "abcd" };
},
},
});لتفعيل TLS، مرر كائن tls يحتوي على حقول key و cert.
Bun.listen({
hostname: "localhost",
port: 8080,
socket: {
data(socket, data) {},
},
tls: {
// يمكن أن يكون سلسلة، BunFile، TypedArray، Buffer، أو مصفوفة منها
key: Bun.file("./key.pem"),
cert: Bun.file("./cert.pem"),
},
});يتوقع حقلا key و cert محتويات مفتاح TLS والشهادة الخاصة بك. يمكن أن يكون هذا سلسلة أو BunFile أو TypedArray أو Buffer.
Bun.listen({
// ...
tls: {
key: Bun.file("./key.pem"), // BunFile
key: fs.readFileSync("./key.pem"), // Buffer
key: fs.readFileSync("./key.pem", "utf8"), // string
key: [Bun.file("./key1.pem"), Bun.file("./key2.pem")], // array of above
},
});نتيجة Bun.listen هي خادم يتوافق مع واجهة TCPSocket.
const server = Bun.listen({
/* config*/
});
// إيقاف الاستماع
// تحدد المعلمة ما إذا كانت الاتصالات النشطة مغلقة
server.stop(true);
// السماح لعملية Bun بالخروج حتى لو كان الخادم لا يزال يستمع
server.unref();إنشاء اتصال (Bun.connect())
استخدم Bun.connect للاتصال بخادم TCP. حدد الخادم للاتصال به مع hostname و port. يمكن لعملاء TCP تعريف نفس مجموعة المعالجات مثل Bun.listen، بالإضافة إلى معالجين خاصين بالعميل.
// العميل
const socket = await Bun.connect({
hostname: "localhost",
port: 8080,
socket: {
data(socket, data) {},
open(socket) {},
close(socket, error) {},
drain(socket) {},
error(socket, error) {},
// معالجات خاصة بالعميل
connectError(socket, error) {}, // فشل الاتصال
end(socket) {}, // تم إغلاق الاتصال بواسطة الخادم
timeout(socket) {}, // انتهت مهلة الاتصال
},
});لفرض TLS، حدد tls: true.
// العميل
const socket = await Bun.connect({
// ... config
tls: true,
});إعادة التحميل الساخن
يمكن إعادة تحميل خوادم TCP والمقابس بشكل ساخن مع معالجات جديدة.
const server = Bun.listen({
/* config */
});
// يعيد تحميل المعالجات لجميع مقابس جانب الخادم النشطة
server.reload({
socket: {
data() {
// معالج 'data' جديد
},
},
});const socket = await Bun.connect({
/* config */
});
socket.reload({
data() {
// معالج 'data' جديد
},
});التخزين المؤقت
حاليًا، لا تخزن مقابس TCP في Bun البيانات مؤقتًا. للكود الحساس للأداء، من المهم النظر في التخزين المؤقت بعناية. على سبيل المثال، هذا:
socket.write("h");
socket.write("e");
socket.write("l");
socket.write("l");
socket.write("o");...أداء أسوأ بكثير من هذا:
socket.write("hello");لتبسيط هذا الآن، فكر في استخدام ArrayBufferSink في Bun مع خيار {stream: true}:
import { ArrayBufferSink } from "bun";
const sink = new ArrayBufferSink();
sink.start({
stream: true,
highWaterMark: 1024,
});
sink.write("h");
sink.write("e");
sink.write("l");
sink.write("l");
sink.write("o");
queueMicrotask(() => {
const data = sink.flush();
const wrote = socket.write(data);
if (wrote < data.byteLength) {
// أعدها إلى sink إذا كان المقبس ممتلئًا
sink.write(data.subarray(wrote));
}
});NOTE
**Corking**الدعم لـ corking مخطط له، لكن في هذه الأثناء يجب إدارة backpressure يدويًا مع معالج drain.