Nasıl çalışır
Bir parça C# kodu yazarsınız. Döndürdüğü şey birkaç saniye içinde HTTPS üzerinden, herkese açık bir adreste yayına girer. Aşağıda her şey, karşılaşacağınız sırayla anlatılıyor.
Lambda nedir?
Lambda, bir GenHTTP handler döndüren bir kod parçasıdır. Platform onu derler, yükler ve döndürdüğü şeyi kendi adresinizin altına bağlar. Proje yok, build dosyası yok, using satırı yok. Tüm GenHTTP modülleri zaten içe aktarılmış durumda.
return Content.From(Resource.FromString("hello"));
Bu, eksiksiz bir lambda. /lambda/your-key/ adresinde yayına alındığında her isteğe “hello” kelimesiyle yanıt verir.
Kod parçası bir sınıf değildir, deyimlerden oluşur. Yaptığı son iş, istekleri karşılayabilen bir şey döndürmektir: bir handler ya da onu oluşturan bir builder.
İlk lambdanız
- 1Lambda oluştur düğmesine basın. Herkese açık bir adres ve bir editör anahtarı alırsınız. Anahtar, geri dönmenin tek yolu. Saklayın, çünkü kimse onu sizin için kurtaramaz.
- 2Ardından lambdanın kontrol paneline gelirsiniz. İlk sürüm olarak küçük bir REST servisi hazır bekler. Bu sadece bir başlangıç.
- 3Editör anahtarını bir ajana verin ve ne yapacağını söyleyin. Ajan MCP üzerinden yeni sürümler yazar. Ya da Kod bölümünü açıp kendiniz yazın: Kontrol et hiçbir şey kaydetmeden derler ve derleyicinin ne dediğini dosya ve satırıyla gösterir.
- 4Yayına al düğmesine basın. Artık yayında. Bundan önce hiçbir şeye erişilemez. Yeniden yayına almak da yayında kalma süresini uzatır.
Kontrol paneli
Editör linki bir metin kutusu değil, bir kontrol paneli açar. Buradaki kodun çoğunu ajanlar yazar, bu yüzden ekranda ilk gördüğünüz şey lambdanızın durumudur. Kenar çubuğunda lambdanın kendisi (yayında olup olmadığı, adresi ve daha yeni bir sürüm yayına alınmayı bekliyorsa bir düğme) ve bölümleri yer alır. Adresi değiştirmek ya da lambdayı silmek gibi nadiren yapılan işler, oradaki ⋯ menüsündedir.
- Genel bakış
- Yayında olup olmadığı, bugün kaç istek aldığı ve kaçının başarısız olduğu, son değişiklik ve ne kadar yer kaldığı.
- Değiştir
- Neyin farklı olması gerektiğini yazın, gerisini bu sunucudaki ajan siz izlerken halleder. Bir taslakta çalışır, değişikliği orada dener ve çalışınca birleştirip bir sonraki sürüm yapar. Taslağı önce kendiniz denemek isterseniz Bitince yayına al seçeneğini kapatın.
- Taslaklar
- Lambdanın yanında üzerinde çalışılan değişiklikler: her biri kendi adresinde denenir ve hazır olunca birleştirilip bir sonraki sürüm olur. Açıldığında bir taslağın kendi kodu, verileri ve logları vardır.
- Dosyalar
- Bir sürümün dosyaları: kodu ve statik dosyaları, yani programın kendisi. Kilit ya da dünya simgesi, herkesin onlara erişip erişemeyeceğini gösterir.
- Veriler
- Lambdanın çalışırken sakladıkları, tüm sürümler için ortak: çalışma alanı. İçine bakın, dosya yükleyip silin ya da onu kapatın.
- Sürümler
- Her sürümün neyi değiştirdiği, ne istendiği ve bir öncekinden farkı. Buradan yayına alabilir, eski bir sürüme dönebilir ya da herhangi bir sürümden bir taslak başlatabilirsiniz.
- Yayın geçmişi
- Ne zaman neyin yayında olduğu ve neden yayından kalktığı.
- İstatistikler
- Son bir saatin ya da günün istekleri, hataları, yanıt süreleri ve en çok istenen yolları.
- Loglar
- İstekler, lambdanın yazdırdıkları ve ters giden her şeyin stack trace’i, anında.
- Kod
- Elle yazmak için. Kontrol et derler, Kaydet bir sürüm oluşturur, Yayına al yayına alır. Bir taslakta ise Kaydet onu taslakta tutar, Önizlemeyi yayına al da taslağın adresinde yayına alır.
Ctrl-Skaydeder,F12bir tanıma gider.
Her bölüm aynı şekilde çalışır: başlığı, onu açıklayan bir ⓘ simgesi, sağda eylemleri ve birden fazla görünümü varsa altında bir sıra sekme. Kod bölümünde bu sekmeler dosyalardır.
Trafik ve log bellekte tutulur. Saklamak için değil, izlemek içindir: sunucu yeniden başlarsa sıfırdan başlarlar. Sürümler ve yayın geçmişi ise kalıcı olarak saklanır.
Nedenini yazmak
Bir sürüm, kod ve isteğe bağlı iki nottan oluşur: spesifikasyon, yani kullanıcının ne istediği ve nedeni, mümkünse kendi sözleriyle; ve değişiklik, yani sürümün ne yaptığını anlatan tek bir satır. İkisi de sürüm geçmişinde diff’in yanında görünür. Böylece neden, ne ile yan yana kalır. Hem sizin için, hem de bir şeyi değiştirmeden önce geçmişi okuyan bir sonraki ajan için.
POST /api/v1/lambdas/{editorKey}/versions { "files": [ { "name": "lambda.cs", "code": "..." } ], "specification": "İnsanların imza atabileceği bir ziyaretçi defteri; kayıtlar yeniden başlatmada kaybolmamalı", "change": "Kayıtları çalışma alanında tutar, böylece yeniden başlatmada kaybolmazlar" }
Ajanlar da aynı iki alanı write_code aracına verir. Kod bölümünde kaydederken değişiklik sorulur. İkisi de isteğe bağlıdır. Uzun bir spesifikasyon reddedilmez, 4.000 karakterde kesilir; değişiklik ise 500 karakterde. Bir taslağın da kendi iki notu vardır; birleştirildiği sürüm bunları devralır.
Güvenle değiştirmek
Bir sürüm, kaydedildikten sonra bir daha değişmez. Her birini saklamaya değer kılan da bu: herhangi biriyle karşılaştırma yapılabilir, herhangi biri tam olduğu gibi yeniden yayına alınabilir. İnsanların kullandığı bir lambdayı değiştirmek için bunun yerine bir taslak başlatın.
- 1Taslaklar bölümünden ya da herhangi bir sürümden başlatın. Taslak, o sürümün kodunun ve statik dosyalarının, bir de lambdanın verilerinin kopyasıdır.
- 2Gerektiği kadar değiştirin: Kod bölümünde ya da ajandan isteyerek. Önizlemeyi yayına al onu kendi adresinde,
/features/…/altında, verilerin kendine ait kopyasıyla yayına alır. Lambdanın ziyaretçileri bunların hiçbirini görmez; taslağın yazdığı hiçbir şey lambdanın verilerine ulaşmaz. - 3Hazır olunca Birleştir düğmesine basın: notlarıyla birlikte bir sonraki sürüm olur ve isterseniz hemen yayına girer. Taslak ise önizlemesi ve verilerin kopyasıyla birlikte kaldırılır.
POST /api/v1/lambdas/{editorKey}/features { "name": "Skor tablosu" } PUT /api/v1/lambdas/{editorKey}/features/{feature}/files?deploy=true POST /api/v1/lambdas/{editorKey}/features/{feature}/merge { "deploy": true }
Aynı anda birden fazla taslak üzerinde çalışılabilir. Yalnızca en yeni sürümü temel alan bir taslak birleştirilebilir; böylece bir birleştirme, taslak başladıktan sonra kaydedilen bir sürümü asla geri almaz. Önce başka bir taslak birleştirildiyse onun değişikliklerini taslağa taşıyın (ya da ajandan isteyin), sonra taslağın temelini en yeni sürüm yapın. Hiçbir şey kendiliğinden birleşmez; bu bilinçli bir tercih.
Birden fazla dosya
Türlerin, onları kullanan kodun altında durması gerekmez. Kod bölümünde dosyaların yanındaki + düğmesine basın. Yeni dosya, kod parçasıyla aynı namespace içinde, onunla birlikte derlenir. Böylece erişmek için hiçbir şeyi içe aktarmanız gerekmez. Uzantısı olmayan bir ad C# dosyası sayılır.
var shelf = new Shelf(); return Inline.Create() .Get(() => shelf.All()) .Post((Book book) => shelf.Add(book));
public sealed class Shelf { private readonly List<Book> _books = []; public IEnumerable<Book> All() => _books; public Book Add(Book book) { _books.Add(book); return book; } } public record Book(string Title, string Author);
Sayfa sunmak
Sayfa sunmanın iki yolu var. İnsanların yanına yüklediği dosyalar için de bir üçüncüsü.
Tek sayfa, kodun içinde
Küçük şeyler için yeterli. Sayfa doğrudan kodun içinde yer alır.
var page = Resource.FromString(""" <!doctype html> <title>Mine</title> <h1>It works</h1> """) .Type(new ContentType("text/html; charset=utf-8")); return Content.From(page);
Gerçek dosyalarla bir klasör
Stil dosyası ve script içeren her şey için doğru seçim. Dosyalar tıpkı bir C# dosyası gibi eklenir ve tam yazıldığı gibi sunulur. Derlenmezler.
return Layout.Create() .Add("api", api) .Add(Assets.App("site"));
Yüklenen dosyalar, verilerden
İnsanların yüklediği ya da lambdanın oluşturduğu şeyler (görseller, belgeler) için; uygulamanın yanında sunulurlar. Uygulamanın kendi sayfaları için değil: onların yeri bir dosya klasörüdür, orada onlara ihtiyaç duyan kodla birlikte sürümlenirler.
return Layout.Create() .Add("api", api) .Add("uploads", Workspace.Files("uploads")) .Add(Assets.App("site"));
Adım adım bir frontend
Bunların ikincisi, baştan sona. Her demo, sayfasını bu şekilde web adlı bir klasörden sunar. Bir örnek görmek için demo-crud demosunu açın. Demolar salt okunurdur; editör anahtarları adlarıyla aynıdır.
- 1Kod bölümünde dosyaların yanındaki + düğmesine basın ve
site/index.htmlyazın. Adında eğik çizgi olan bir dosya bir klasöre girer. Uzantısı olan bir ad da uzantısının söylediği türde dosya sayılır. - 2
site/app.cssvesite/app.jsdosyalarını da aynı şekilde ekleyin. Sayfanız onlarahref="app.css"örneğindeki gibi adlarıyla başvurur. Çünkü klasör adresin bir parçası değil, sunulan içeriğin köküdür. - 3Görsel ya da font gibi metin olmayan dosyalar için
siteklasöründeki bir dosyayı açın ve dosyaların yanındaki yükleme düğmesine basın. Dosya aynı klasöre gider. PNG bir metin editöründe yazılamaz, o yüzden yolu bu. - 4
lambda.csdosyasında klasörü sunun:return Layout.Create().Add(Assets.App("site"));
- 5Yayına al düğmesine basın.
site/index.htmldosyası/adresinde,site/app.cssdosyası/app.cssadresinde yanıt verir. Hiçbir dosyayla eşleşmeyen her adreste sayfanın kendisi döner. Böylece kendi yönlendirmesini yapan bir frontend, biri bir deep link üzerinde sayfayı yenilediğinde de çalışır. - 6Yanına bir API ekleyin, sayfanın konuşacağı bir şey olsun:
var api = Inline.Create().Get("notes", () => notes); return Layout.Create() .Add("api", api) .Add(Assets.App("site"));
Dosyaların durduğu iki yer
Bir lambda dosyaları iki yerde tutar ve editör onları ayrı gösterir: Dosyalar bir sürümün dosyalarını (programı), Veriler ise çalışma alanını (programın sakladıklarını) tutar. Fark, kime ait olduklarında yatar. Bir sürümün dosyaları o sürüme aittir; veriler ise lambdaya aittir ve her sürüm onları paylaşır.
| Bir sürümde | Verilerde | |
|---|---|---|
| ne tutar | kod ve statik dosyalar: frontend dahil programın kendisi | lambdanın yazdığı ya da birinin yüklediği her şey |
| ne zaman değişir | hiçbir zaman: her değişiklik yeni bir sürümdür | içine bir şey yazıldığı anda |
| yayına alma | tam olarak bu dosyaları yayına alır | ona hiç dokunmaz |
| eski bir sürüme dönmek | eski dosyaları geri getirir | etkisi yok: her sürüm onu paylaşır |
| bir taslak | onların bir kopyasıyla başlar | onun bir kopyası üzerinde çalışır |
| ne zaman silinir | sınır aşılınca, eski sürümlerle birlikte | lambdayla birlikte ya da siz kapattığınızda |
| koddan erişim | Assets | Workspace |
İkisi tek bir yer olamaz. Olsaydı, her yayına alma ya lambdanızın o zamandan beri yazdığı her şeyi silerdi ya da yayına aldığınız dosyalardan hiçbir şey kaldırılamazdı. Skor tablosu tutan bir oyun ikincisini ister, sunduğu sayfa ise birincisini. Bu yüzden sayfa sürüme, skor tablosu da verilere girer.
Veri saklamak
Workspace, lambdanızın okuyup yazabildiği özel bir klasördür. Bir istekten ya da bir yayından daha uzun yaşaması gereken her şeyin yeri burasıdır.
var notes = new List<string>(); if (Workspace.Exists("notes.json")) { notes.AddRange(JsonSerializer.Deserialize<List<string>>(Workspace.ReadText("notes.json")) ?? []); } return Inline.Create() .Get("notes", () => notes) .Post("notes", (string text) => { notes.Add(text); Workspace.WriteText("notes.json", JsonSerializer.Serialize(notes)); return notes.Count; });
Ayrıca ReadBytes, WriteBytes, Delete, List, CreateFolder ve içeriği sunmak için Tree/Files/App da var. Dosya sisteminin geri kalanına erişilemez.
Websocket’ler
Destekleniyor, hem de sonradan akla gelmiş bir özellik olarak değil. demo-game demosu oyuncuları eşleştirir ve her oyunu sunucuda yürütür. En basit hâli üç callback’ten oluşur:
var room = new ConcurrentDictionary<IReactiveConnection, string>(); var socket = Websocket.Functional() .OnOpen(c => { room[c] = "someone"; return ValueTask.CompletedTask; }) .OnMessage(async (c, text) => { foreach (var other in room.Keys) { await other.WritePayloadAsync(text); } }) .OnClose((c, _) => { room.TryRemove(c, out _); return ValueTask.CompletedTask; }); return Layout.Create().Add("chat", socket);
Herkesin takıldığı bir nokta var: tarayıcı, websocket el sıkışmasında header ekleyemez. Handler’ın ihtiyaç duyduğu bilgiyi sorgu parametrelerinde gönderin; handler onu connection.Request.Header.Query üzerinden okur. Ya da gizli bilgileri ilk mesaj olarak gönderin.
İzin verilmeyenler
Kodunuz ortak bir sunucuda çalışır. Bu yüzden C# dilinin bazı kısımları derlenmeden önce reddedilir: süreç başlatmak, kendi soketlerinizi açmak, assembly yüklemek, çalışma alanınızın dışında dosya sistemine erişmek ve bunları aşmak için reflection kullanmak.
Geri kalan her şey mevcut, GenHTTP modül API’sinin tamamı dahil. Bir şey reddedilirse sadece başarısız olduğu değil, hangi satırda ve neden reddedildiği de söylenir.
Kodunuzu alıp gitmek
Editördeki .NET projesi olarak indir ile lambdanın tamamını alırsınız: açabileceğiniz, dotnet run ile çalıştırabileceğiniz ve saklayabileceğiniz bir solution. İçinde tek bir paket referansı var, bu platformdan ise hiçbir iz yok.
Kod parçanız Program.cs dosyasının gövdesi olur ve döndürdüğü şeyi sunan bir host içine yerleşir. Diğer dosyalarınız tam yazdığınız gibi gelir. Workspace ve Assets kodun yanında iki klasör olur ve aynı metotlarla çalışır. Yani kodunuzda hiçbir şeyi değiştirmeniz gerekmez.
Burada bir şey yapmadan önce bilmekte fayda var: yazdığınız kod sizindir ve eksiksiz olarak sizinle gelir. Onu bu makinede çalıştırmak, onu bu makineye bağlamaz.
İşi bir ajana bırakmak
/mcp adresinde bir MCP endpoint’i var. Bir ajanı buraya bağlayın, editörün yaptığı her şeyi yapabilir: kılavuzu okur, bir demoyu baştan sona inceler, dosya yazar, derler ve yayına alır. Altta aynı API çalışır.
Ajan çalışırken nedenini de söyler (write_code aracı spesifikasyonu ve değişikliği alır) ve yayına aldığı şeye bakabilir: read_logs aracı lambdanın son isteklerini, yazdırdıklarını ve fırlattığı her hatanın stack trace’ini döndürür. Ajan, kodunun çalıştığını varsaymak yerine böyle öğrenir. Siz de aynı şeyi kontrol panelinde izlersiniz.