Routing dile gömülü. DB bağlantısı kalıcı. WebSocket, SSE, parallel(), jobs::, template:: — hepsi tek binary içinde. Framework kurma, sadece yaz.
use cache; $conn = db::connect("mysql://root:@127.0.0.1/shop"); # REST — JSON API route("GET", "/api/dashboard", function() use ($conn) { $ch = channel(3); parallel(function() use ($ch, $conn) { send($ch, db::col($conn, "SELECT count(*) FROM orders", [])); }); parallel(function() use ($ch, $conn) { send($ch, db::col($conn, "SELECT sum(total) FROM orders", [])); }); parallel(function() use ($ch, $conn) { send($ch, db::col($conn, "SELECT count(*) FROM users", [])); }); print(json::encode(["orders" => receive($ch), "revenue" => receive($ch), "users" => receive($ch)])); }); # SSE — canlı bildirim akışı route("SSE", "/events", function($sse) { $id = timer::every(3000, function() use ($sse) { sse::send($sse, json::encode(["t" => date::now()]), "tick"); }); sse::on($sse, "close", function() use ($id) { timer::cancel($id); }); });
LOOK, sunucu taraflı web geliştirme için tasarlanmış bir scripting dilidir. Routing, DB, eşzamanlılık, gerçek zamanlı bağlantılar, arka plan işler ve şablon motoru — hepsi tek binary içinde, sıfır bağımlılıkla.
Uygulama bir kez başlar. DB bağlantısı, route kayıtları, setup kodu — hepsi bellekte kalır.
Her HTTP isteği sadece dispatch_routes() çalıştırır.
32 worker, 4.7 milyon istek, 10 dakika — 0 hata, 8 MB RAM.
route("GET", "/urun/{id}", fn) — bu bir kütüphane çağrısı değil, dilin çekirdeği.
Router kurmak yok, config yok, middleware stack yok.
REST, WebSocket, SSE — hepsi aynı route() sözdizimi ile.
Go goroutine felsefesi, web scripting dilinde. 3 DB sorgusunu aynı anda çalıştır,
sonuçları receive() ile topla — toplam süre max(t₁, t₂, t₃).
Eşzamanlılık için ek runtime, ek kütüphane, ek öğrenme yok.
route("WS", "/chat", fn) — WebSocket, RFC 6455 tam uyumlu.
route("SSE", "/events", fn) — Server-Sent Events, timer::every() ile birlikte.
500 eşzamanlı WebSocket bağlantısı, 72 saat, 0 bellek sızıntısı.
looktest.tobiyo.com.tr · AlmaLinux 8 · MariaDB · 32 worker ile ölçüldü.
Tüm testler looktest.tobiyo.com.tr canlı ortamında
wrk / ab ile ölçülmüştür.
DB-bound endpoint'ler ~380 RPS — darboğaz MySQL RTT (~2.6ms), LOOK değil.
WebSocket: 500 eşzamanlı bot, 72 saat RSS sabit.
Hiçbir şey kurmadan, hiçbir şeyi öğrenmeden doğrudan yazın.
route("GET", "/urun/{id}", fn) — REST, WS, SSE aynı sözdizimi. URL parametresi otomatik parse.
Sıfır bağımlılık, wire protocol doğrudan implement. Aynı API: db::query / db::exec / db::col.
Go goroutine stili. Fan-out, pipeline, producer-consumer — kanal üzerinden. Blocking yok, callback yok.
route("WS", "/chat", fn) — RFC 6455, SHA-1+Base64 handshake. ws::broadcast() tüm bağlı istemcilere.
route("SSE", "/events", fn) — Server-Sent Events. timer::every(3000, fn) ile periyodik push.
SQLite tabanlı kalıcı kuyruk. jobs::push / worker / run. Delayed jobs, retry, dead-letter. Process kapanınca kaybolmaz.
In-memory, thread-safe, isimlendirilmiş kuyruk. Request'ler arası veri aktarımı. queue::push / pop / peek / size.
TTL destekli, thread-safe singleton. Warm start'ta tüm worker'lar paylaşır. cache::get / set / has / flush.
Layout kalıtımı, partial include, {#each} döngüsü, {#if} koşulu. Svelte gibi — runtime yok, sadece sunucu render.
AST → register-based bytecode → switch dispatch. Compute-heavy workload'da interpreter'a göre 7.8× hız artışı.
Mailgun, SendGrid, Postmark destekli. mail::send / send_html. MAIL_PROVIDER env ile provider seçimi.
look test — 10 assertion, before_each/after_each. look repl — interaktif. look install github.com/user/pkg.
$conn = db::connect("mysql://root:@127.0.0.1/blog"); use auth; use validator; use cache; function admin_kontrol() { session::start(); if (session::get("admin_id") == null) { response::status(401); print(json::encode(["ok" => false, "hata" => "Yetkisiz"])); return false; } return true; } route("GET", "/api/yazilar", function() use ($conn) { # 5 dakika cache — aynı veriyi defalarca DB'den çekme $data = cache::get("yazilar"); if ($data == null) { $data = db::query($conn, "SELECT * FROM yazilar ORDER BY id DESC", []); cache::set("yazilar", $data, 300); } print(json::encode(["ok" => true, "data" => $data])); }); route("POST", "/api/yazilar", function() use ($conn) { if (!admin_kontrol()) { return; } $v = validator::check(request::json(), [ "baslik" => ["required", "min:3", "max:200"], "icerik" => ["required", "min:10"] ]); if (!$v["ok"]) { response::status(422); print(json::encode($v)); return; } $data = request::json(); db::exec($conn, "INSERT INTO yazilar (baslik,icerik) VALUES (?,?)", [$data["baslik"], $data["icerik"]]); cache::delete("yazilar"); # cache invalidate print(json::encode(["ok" => true, "id" => db::last_id($conn)])); });
# Hub: tüm bağlantıların ortak yayın kanalı (setup fazında) $hub = channel(); route("WS", "/chat", function($ws) use ($hub) { # Her bağlantı için bir goroutine: hub'dan dinle → bu client'a yaz parallel(function() use ($ws, $hub) { while (true) { $msg = receive($hub); if ($msg == null) { break; } ws::send($ws, $msg); } }); # Mesaj gelince hub'a gönder → tüm clientlar duyar ws::on($ws, "message", function($data) use ($hub) { $p = json::decode($data); send($hub, json::encode(["from" => request::ip(), "msg" => $p["msg"]])); }); ws::on($ws, "close", function() { log::info("Bağlantı kapandı — aktif: " . ws::clients()); }); }); # Keepalive ping — her 30 saniyede tüm clientlara timer::every(30000, function() { ws::broadcast(json::encode(["type" => "ping"])); });
$conn = db::connect("mysql://root:@127.0.0.1/shop"); route("GET", "/panel/ozet", function() use ($conn) { $ch = channel(3); # 3 sonuç beklenecek parallel(function() use ($ch, $conn) { send($ch, db::col($conn, "SELECT count(*) FROM siparisler", [])); }); parallel(function() use ($ch, $conn) { send($ch, db::col($conn, "SELECT sum(toplam) FROM siparisler WHERE durum='odendi'", [])); }); parallel(function() use ($ch, $conn) { send($ch, db::col($conn, "SELECT count(*) FROM kullanicilar WHERE aktif=1", [])); }); # Tüm goroutine'ler bitmeden devam etmez $siparisler = receive($ch); $gelir = receive($ch); $kullanicilar = receive($ch); print(json::encode([ "siparisler" => $siparisler, "gelir" => $gelir, "kullanicilar" => $kullanicilar ])); });
$conn = db::connect("mysql://root:@127.0.0.1/shop"); # SSE: tarayıcı bağlandığında sürekli veri akışı gönderilir route("SSE", "/canli/siparisler", function($sse) use ($conn) { # Her 2 saniyede yeni sipariş kontrolü $tick = timer::every(2000, function() use ($sse, $conn) { $yeni = db::query($conn, "SELECT * FROM siparisler WHERE olusturma > date_sub(now(), interval 5 second)", []); if (count($yeni) > 0) { $ok = sse::send($sse, json::encode($yeni), "yeni_siparis"); if (!$ok) { timer::cancel($tick); } # bağlantı kapandı } }); # 30s keepalive — tarayıcı timeout etmesin $ping = timer::every(30000, function() use ($sse) { sse::send($sse, "keepalive", "ping"); }); sse::on($sse, "close", function() use ($tick, $ping) { timer::cancel($tick); timer::cancel($ping); log::info("SSE kapandı — aktif: " . sse::clients()); }); });
use jobs; use mail; # Route: isteği anında yanıtla (1ms), işi kuyruğa at route("POST", "/kayit", function() use ($conn) { $data = request::json(); db::exec($conn, "INSERT INTO kullanicilar (email,ad) VALUES (?,?)", [$data["email"], $data["ad"]]); # max 3 deneme, hemen işle (delay_sec=0) jobs::push("hosgeldin_email", ["to" => $data["email"], "ad" => $data["ad"]], 3, 0); # 10 dakika sonra hatırlatma maili jobs::push("hatirlatma_email", ["to" => $data["email"]], 3, 600); print(json::encode(["ok" => true])); }); # worker.lk — ayrı process (systemd servis olarak çalışır) jobs::recover("hosgeldin_email"); # crash recovery jobs::worker("hosgeldin_email", function($job) { $r = mail::send($job["payload"]["to"], "Hoş geldiniz!", "Merhaba " . $job["payload"]["ad"] . ", kaydınız tamamlandı."); return $r["ok"]; # false → retry (max 3), sonra dead-letter }); jobs::run(5000); # 5 saniyede bir poll
use template; # Struct — Go stili, method yok, sadece veri struct Yazi { id baslik icerik tarih begeni: 0 yayinda: true } $tpl = env("VIEWS_DIR", "/app/views"); route("GET", "/blog", function() use ($conn, $tpl) { $rows = db::query($conn, "SELECT * FROM yazilar WHERE yayinda=1", []); print(template::render($tpl . "/blog/index", [ "baslik" => "Blog", "yazilar" => $rows ])); }); # views/blog/index.html — sunucu taraflı, JS yok # {#extends "views/layout/base"} # {#block "content"} # {#each $yazilar as $y} # <article> # <h2>{$y.baslik}</h2> # <p>{$y.tarih} · {$y.begeni} beğeni</p> # <div>{!$y.icerik}</div> # </article> # {/each} # {#empty}<p>Henüz yazı yok.</p>{/each} # {/block}
Aynı iş, daha az kod, daha az sürpriz.
| Konu | PHP | LOOK |
|---|---|---|
| DB bağlantısı | Her request yeni bağlantı | Warm start — bir kez açılır |
| Global değişken | $_GET, $_POST, $_SESSION... | Yok — request:: / session:: |
| Routing | Framework (Laravel, Slim...) | Dile gömülü — route() |
| SQL injection koruması | Manuel bind_param | db::query otomatik parametreli |
| Eşzamanlılık | pcntl_fork / ext | parallel() + channel() dilde |
| WebSocket | Ratchet / Swoole gerekir | route("WS",...) — dahil |
| Performans (router) | ~500–2000 RPS (FPM) | 8.276 RPS (VM, Apache bypass) |
Her yeni özellik bu üç ilkeye hizmet etmek zorunda — yoksa dile girmez.
use() ile ne girdiği bildirilir.
Gizli global değişken yok, sürpriz yok.
LOOK'un tüm bileşenleri sıfır bağımlılıkla C++23 ile yazılmıştır.
Precedence-aware parser, tam operatör seti, string interpolation, SourceLocation ile hata konumu.
AST → 3-adres register bytecode → switch dispatch. Compute workload'da 7.8× hız. Fallback: tree-walk interpreter.
--workers N, per-request interpreter kopyası, per-DSN bağlantı havuzu. Hot reload: sıfır kesinti.
epoll (Linux), IOCP (Windows). RFC 6455 WS, SSE frame codec. Sınırsız eşzamanlı bağlantı.
Wire protocol sıfırdan. Sürücü yok, ORM yok. Aynı db:: API, farklı DSN.
Apache/nginx FastCGI, standalone HTTP, CGI fallback. Tek binary, üç mod.
Platform seçin:
GitHub Releases'tan platforma uygun arşivi indir ve çıkart.
tar -xzf look-linux-x86_64.tar.gz
cp look-fcgi /opt/look/ && chmod +x /opt/look/look-fcgi
systemd servisi yaz (bkz. Docs → FastCGI) veya doğrudan:
look-fcgi --port 9000 --workers 8
look-fcgi version # LOOK 1.0.0 (linux/amd64)
XAMPP zaten kuruluysa bu adımı atlayın.
Binary'leri kopyalar, Apache'yi yapılandırır, Task Scheduler servisi kaydeder.
install.bat --xampp C:\xampp
XAMPP Control Panel → Apache → Restart. http://localhost/ açın — çalışıyor.
Plesk → Extensions → ZIP Yükle → look-lang-1.0.0.zip
LOOK → Domain Ekle → domain seç, worker sayısı, mod (fcgi / http) → Başlat.
Terminal yok, SSH yok, config yok. systemd + nginx vhost otomatik oluşturuldu.
Docker, LOOK binary'lerini derlemek için kullanılır. Ubuntu 24.04 ve AlmaLinux 8 için ayrı Dockerfile mevcuttur.
docker build -f Dockerfile.linux-build -t look-builder .
docker run --rm -v "${PWD}:/src" look-builder sh -c "cd /src/build-linux && cmake .. -DCMAKE_BUILD_TYPE=Release && make -j4"
cpp/build-linux/look-fcgi # hazır binary
AlmaLinux 8 (Plesk) için Dockerfile.almalinux8-build kullanın — glibc farkı nedeniyle Ubuntu binary AlmaLinux'ta çalışmaz.
v1.0.0 · Apache 2.0 · Tüm platformlar için kararlı sürüm.
Ubuntu 22.04 / 24.04. Apache veya nginx ile. glibc 2.31+.
⇓ GitHub Releases → Kurulum RehberiAlmaLinux 8 / RHEL 8. Plesk sunucuları için. glibc 2.17 uyumlu build.
⇓ GitHub Releases → Plesk KurulumuWindows 10/11 + XAMPP. IOCP — sınırsız bağlantı. Task Scheduler ile otomatik başlatma.
⇓ GitHub Releases → XAMPP Kurulum RehberiPlesk 18+ için tek tıkla kurulum. Domain ekle, başlat — terminal yok, SSH yok.
⇓ look-lang-1.0.0.zip → GitHub →Sözdizimi renklendirme, 30+ snippet, bracket matching. Tüm modüller dahil. v0.1.0
⇓ Marketplace'ten Kur → VSIX İndir (Manuel)C++23, CMake 3.20+. Apache 2.0 lisansı. Katkı yapmak veya kendin derlemek için.
GitHub → codlook/look Tüm Sürümler