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.
SHA-256, HMAC-SHA256, UUID v4, timing-safe compare — sıfır bağımlılık. Resmi pkg/jwt paketi ile HS256 token imzala ve doğrula.
GET, POST, PUT, PATCH, DELETE. JSON body, özel başlıklar, timeout. TLS dahil. parallel() ile fan-out paralel API çağrısı.
look install github.com/Codlook/look-packages — JWT, ödeme ve daha fazlası. look-modules topluluk modülleri. Registry yok, config yok.
look test — 10 assertion, before_each/after_each. look repl — interaktif. look install github.com/user/repo ile GitHub'dan paket kur.
$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}
# Terminal: look install github.com/Codlook/look-packages use "pkg/jwt/jwt.lk" use auth use crypto $conn = db::connect(env("DB_DSN", "mysql://root:@127.0.0.1/app")) # Giriş — token üret route("POST", "/api/giris", function() use ($conn) { $email = request::post("email") ?? "" $sifre = request::post("sifre") ?? "" $rows = db::query($conn, "SELECT * FROM users WHERE email=?", [$email]) if (count($rows) == 0 || !auth::verify($sifre, $rows[0]["sifre_hash"])) { response::status(401) print(json::encode(["ok" => false, "hata" => "Hatalı giriş"])) return } $token = jwt_sign( ["user_id" => $rows[0]["id"], "rol" => $rows[0]["rol"]], env("JWT_SECRET", ""), ["exp" => 86400] # 24 saat ) print(json::encode(["ok" => true, "token" => $token])) }) # Korumalı endpoint — Bearer token zorunlu function auth_required() { $header = request::header("Authorization") ?? "" $token = string::substr($header, 7) # "Bearer " kaldır $p = jwt_verify($token, env("JWT_SECRET", "")) if ($p == null) { response::status(401) print(json::encode(["error" => "Geçersiz token"])) return null } return $p } route("GET", "/api/profil", function() use ($conn) { $user = auth_required() if ($user == null) { return } $rows = db::query($conn, "SELECT id,ad,email FROM users WHERE id=?", [$user["user_id"]]) print(json::encode(["ok" => true, "data" => $rows[0]])) }) # Webhook doğrulama — HMAC-SHA256 timing-safe route("POST", "/webhook/odeme", function() { $payload = request::body() $verilen = request::header("X-Signature") ?? "" $beklenen = "sha256=" . crypto::hmac_sha256($payload, env("WEBHOOK_SECRET", "")) if (!crypto::constant_compare($verilen, $beklenen)) { response::status(401) return } # İmza geçerli — ödeme işlemi... print(json::encode(["ok" => true])) })
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 Panel → Server Management → Terminal
SSH tercih ediyorsanız: ssh root@sunucu_ip
rm -rf look-lang && wget -L -O look-lang.zip "https://github.com/codlook/look/releases/download/v1.2.0/look-lang-plesk-1.2.0.zip" && unzip -o look-lang.zip -d look-lang && sed -i "s/\r//" look-lang/setup.sh && plesk bin extension --uninstall look-lang 2>/dev/null; bash look-lang/setup.sh
"[LOOK] Kurulum tamamlandi" mesajı ve panel adresi görünür. Eklenti zaten kuruluysa otomatik kaldırılıp yeniden kurulur.
Plesk Panel → Extensions → My Extensions → LOOK Language → Aç
"Sayfayı Yenile" butonuna basın. Ana ekranda + Domain Ekle → domain seçin → Ekle ve Başlat
≈5 saniye sonra domain listesinde active görünür. systemd servisi otomatik oluşturulur.
Domain'in httpdocs/ klasörüne index.lk dosyanızı koyun — LOOK otomatik algılar, restart gerekmez.
Toplam süre: ~3 dakika — 2 terminal komutu, 1 kez.
Eklenti güncellemelerinde bootstrap yeniden çalıştırmaya gerek yoktur.
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-plesk-1.2.0.zip → GitHub →Sözdizimi renklendirme, 40+ snippet, bracket matching. cache, queue, jobs, mail, http, crypto, JWT dahil. v1.2.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