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.
app::set("db", db::connect("mysql://root:@127.0.0.1/shop")) # REST — 3 sorgu paralel, DB'ye capture'sız erişim (app::db) route("GET", "/api/dashboard", function() { $ch = channel(3) parallel(function() use ($ch) { send($ch, db::col(app::db(), "SELECT count(*) FROM orders", [])) }) parallel(function() use ($ch) { send($ch, db::col(app::db(), "SELECT sum(total) FROM orders", [])) }) parallel(function() use ($ch) { send($ch, db::col(app::db(), "SELECT count(*) FROM users", [])) }) response::json(["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.
Hafif eşzamanlılık, 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ı.
Bir framework değil, bir dil. Aşağıdaki ihtiyaçlardan biri sendeyse LOOK tam sana göre.
Paylaşımlı hosting / Plesk kolaylığını seviyorsun ama WebSocket, SSE ve
eşzamanlılık istiyorsun. Dosyayı at, çalışsın — üstüne gerçek zamanlı bağlantı
ve parallel().
Routing, DB (MySQL/SQLite/PostgreSQL), validation, cache, JWT — hepsi dilde
gömülü. composer/npm bağımlılık ağacı yok, tek binary.
VPS'e tek dosya kopyala, systemd/Plesk ile çalıştır. Ayrı runtime yok, paket yöneticisi yok, sürpriz yok. 1M istek boyunca 28 MB RAM, sabit.
Gömülü SMTP + IMAP sunucusu — Postfix/Dovecot gerekmez. LOOK ile güvenli mail sistemi, e-ticaret bildirimi, blog yaz. Nasıl? ↓
look.codlook.com · AlmaLinux 8 · MariaDB · direkt port, 64 worker ile ölçüldü.
Tüm testler look.codlook.com canlı ortamında
ab ile ölçülmüştür. Throughput c=1.000'den c=20.000'e sabit (~7.5–10k) — darboğaz CPU,
kernel duvarları (backlog, syn_backlog) tuning ile aşıldı. TLS zinciri (nginx→FCGI) ~1.100–1.240 RPS;
fark çift TLS terminasyonundan, LOOK değil. DB-bound endpoint'ler MySQL RTT ile sınırlı.
Sıfır bağımlılık, her satırı test edilmiş. Fuzzing, ThreadSanitizer ve veri bütünlüğü testlerinden geçti.
| Konu | LOOK koruması |
|---|---|
| SQL injection | db::query($c, sql, [params]) — ? otomatik parametreli, driver-doğru escape |
| DoS — devasa gövde | LOOK_MAX_BODY_SIZE (10 MB) aşımı → 413; sınırsız body bellek tüketimi engellendi |
| Request smuggling | Content-Length + Transfer-Encoding birlikte → 400 (RFC 7230 §3.3.3) |
| Bozuk header | Malformed Content-Length → 400 (worker çökmez); chunked TE tam RFC 7230 desteği |
| Slowloris / yavaş istek | Read/write timeout (30s) + kernel backlog 16384 + syn_backlog tuning |
| Session güvenliği | 128-bit /dev/urandom token; cookie HttpOnly + Secure + SameSite |
| Şifre saklama | auth::hash / verify — PBKDF2-SHA256, çekirdekte |
| Upload güvenliği | Magic byte tip doğrulama (uzantı sahteciliğini engeller) + SHA-256 |
| JSON stack overflow | Derin iç içe JSON body → özyineleme derinlik limiti (JSON_MAX_DEPTH) — stack taşması engellendi |
| Protokol parser DoS | RESP2/HTTP/PG/SMTP: korumasız sayı dönüşümü + sınırsız allocation kapatıldı (bozuk sunucu yanıtı worker'ı çökertemez) |
| Aritmetik UB | Signed-integer overflow, shift ve unary-minus tanımsız davranışı giderildi (taşmada float'a promote) — UBSan temiz |
Her build öncesi 9 regresyon testi + CI'da otomatik ASan/UBSan fuzzing ve ThreadSanitizer koşar
(.github/workflows/security.yml). Bellek: 1.75M istek boyunca RSS sabit — sızıntı yok.
Çoğu scripting dili mail gönderir; LOOK mail sunar. Gömülü SMTP (RFC 5321) ve IMAP4rev1 (RFC 3501 + IDLE) sunucusu — Postfix/Dovecot gerekmez. LOOK ile baştan sona güvenli bir mail sistemi yazabilirsin.
Thunderbird, Roundcube, Apple Mail ve mobil istemciler doğrudan bağlanır — listeler, okur, yazar, arar, anlık bildirim alır. Hepsi TLS altında.
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.
fn($x) => $x * 2 — function takma adı + ifade-gövdeli ok, otomatik return. route("GET","/ping", fn() => response::json(["ok"=>true])). Klasik function da geçerli.
Paylaşılan bağlantıyı her route'a use ($conn) ile taşımaya son. app::set("db", $conn) setup'ta bir kez → route'lar capture'sız app::db(). Açık capture felsefesi korunur.
Sıfır bağımlılık, wire protocol doğrudan implement. Aynı API: db::query / db::exec / db::col. Transaction: db::begin / commit / rollback.
LOOK task modeli. Fan-out, pipeline, producer-consumer — kanal üzerinden. Blocking yok, callback yok. parallel::active() / limit() / at_capacity() ile izle.
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, RS256, UUID v4, timing-safe compare — sıfır bağımlılık. Resmi pkg/jwt paketi ile HS256/RS256 token imzala ve doğrula.
İki katmanlı koruma: per-IP burst toleransı + global botnet sınırı. LOOK_RATE_LIMIT_RPM, LOOK_RATE_LIMIT_BURST, LOOK_RATE_LIMIT_GLOBAL_RPM. LOOK kodu değişmez — runtime seviyesinde.
Outbound e-postalar RSA-SHA256 ile otomatik imzalanır (LOOK_SMTP_DKIM_*). Port 25 relay engellendi — sadece kimlik doğrulamalı SMTP (587/465).
Sıfır bağımlılık MTA (25/587) + IMAP4rev1 sunucu (143/993). SMTP mektubu Maildir'e teslim eder, IMAP Thunderbird/Roundcube'e sunar. STARTTLS, SEARCH, canlı IDLE push. Aynı mail_users pbkdf2 kimliği. Dovecot/Postfix gerekmez.
error::new($kod, $mesaj) ile yapılandırılmış hata nesnesi. error::is($e), error::code($e), error::message($e). use gerektirmez — her zaman aktif.
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::error(401, "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) } response::json(["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::json($v, 422) return } $data = request::json() db::exec($conn, "INSERT INTO yazilar (baslik,icerik) VALUES (?,?)", [$data["baslik"], $data["icerik"]]) cache::delete("yazilar") # cache invalidate response::json(["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 iş parçacığı: 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 paralel işler bitmeden devam etmez $siparisler = receive($ch) $gelir = receive($ch) $kullanicilar = receive($ch) response::json([ "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) response::json(["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::error(401, "Hatalı giriş") return } $token = jwt_sign( ["user_id" => $rows[0]["id"], "rol" => $rows[0]["rol"]], env("JWT_SECRET", ""), ["exp" => 86400] # 24 saat ) response::json(["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::json(["error" => "Geçersiz token"], 401) 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"]]) response::json(["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... response::json(["ok" => true]) })
LOOK kodunu kurulum yapmadan tarayıcıda yazıp çalıştır. Şu an geliştiriliyor — hazır olduğunda burada canlı bir editör olacak.
Şimdilik: indir ve lk --mode http ile saniyeler içinde çalıştır.
Login ve veri çekme — tek dosya, çerçeve yok, sürpriz yok.
| Konu | LOOK'ta nasıl |
|---|---|
| DB bağlantısı | Warm start — bir kez açılır, tüm isteklerde canlı kalır |
| İstek verisi | Global yok — request:: / session:: ad alanı |
| Routing | Dile gömülü — route("GET", "/yol/{id}", fn) |
| SQL injection koruması | db::query otomatik parametreli (? placeholder) |
| Eşzamanlılık | parallel() + channel() dilin içinde |
| WebSocket / SSE | route("WS", ...) — çekirdeğe dahil |
| Performans (router) | Bytecode VM — direkt portta 10.000+ RPS, tek çekirdek |
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.3.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
plesk bin extension --uninstall look-lang 2>/dev/null; wget -O /tmp/look-lang-plesk-1.3.0.zip "https://github.com/codlook/look/releases/download/v1.2.0/look-lang-plesk-1.3.0.zip" && plesk bin extension --install /tmp/look-lang-plesk-1.3.0.zip
"The extension was successfully installed." mesajı görünür. v1.3.0 ile kurulum sonrası ekstra komut gerekmez.
Plesk Panel → Extensions → My Extensions → LOOK Language → Aç
Panel açılınca otomatik kurulum tamamlanır. + Domain Ekle → domain seçin → Ekle ve Başlat
≈3 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: ~2 dakika — 1 komut, ekstra adım yok.
v1.3.0 ile panel açılınca kurulum otomatik tamamlanır.
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.4.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.3.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