Skip to Content

IronFlock SDK

IronFlock SDK, edge uygulamalarınızın IronFlock platformuyla etkileşim kurmasını sağlar. Aynı işlevselliğe sahip üç dilde sunulur — Python, JavaScript ve Go — ve aşağıda yan yana belgelenmiştir. Kayıtlı bir cihazda çalışırken kimlik doğrulamayı otomatik olarak yönetir; veri yayımlama, geçmiş sorgulama, cihazlar arası uzak prosedür çağırma ve cihaz meta verisini güncelleme işlevleri sunar.

SDKPaketGereklilik
Pythonironflock on PyPIPython 3.11+
JavaScriptironflock on npmNode.js 22+ veya modern tarayıcı
Gogithub.com/ironflock/sdk-goGo 1.27.2+

Bu sayfa, üç SDK’nın kılavuzudur. Her SDK’nın eksiksiz referansı, GitHub’daki README dosyasıdır: IronFlock/sdk-py, IronFlock/sdk-js ve IronFlock/sdk-go.

Kurulum

pip install ironflock

Ya da uygulamanızın requirements.txt dosyasına ironflock ekleyin.

Hızlı Başlangıç

import asyncio from datetime import datetime, timezone from ironflock import IronFlock async def main(): while True: await ironflock.publish_to_table("sensordata", { "tsp": datetime.now(timezone.utc).isoformat(), "temperature": 22.5, "humidity": 60 }) await asyncio.sleep(5) ironflock = IronFlock(mainFunc=main) ironflock.run()

Bir IronFlock uygulama container’ı içinde kullanıldığında SDK, bağlantı kimlik bilgilerini ortamdan otomatik olarak okur — manuel yapılandırma gerekmez. Bir tabloya yazdığınız her satır, zaman damgası olan bir tsp taşır (bkz. publishToTable).

Yapıcı Seçenekleri

ironflock = IronFlock( mainFunc=main, # async function to run after connecting serial_number="abc123", # override device serial (optional) reconnect_window=60, # seconds an operation rides out a platform restart (optional) )
ParametreAçıklama
mainFuncBağlantı kurulduktan sonra çalışan bir async fonksiyon (async def). Fonksiyon döndüğünde veya bir istisna yükselttiğinde run() ve run_async() bağlantıyı durdurur (bkz. Bağlantı Özellikleri & Yaşam Döngüsü)
ironFlockUrlRouter’ın WebSocket URL’si, ör. wss://cbw.ironflock.com/ws-ua-usr. Verilmezse SDK, URL’yi ortamdan alır (bkz. Ortam Değişkenleri)
serial_numberYayımlarla ve tablo yazmalarıyla gönderilen cihaz seri numarasını geçersiz kılar. Varsayılan: DEVICE_SERIAL_NUMBER ortam değişkeni. Cihaz ajanı uygulama başına bir kimlik bilgisi enjekte ettiği sürece, bağlantının kimlik doğrularken kullandığı kimliği değiştirmez
reconnect_windowTablo işlemlerinin, publish, subscribe ve register_device_function’ın bir yeniden başlatmanın ardından hata yükseltmeden önce platformun geri gelmesini bekledikleri saniye sayısı. Varsayılan 60; 0 beklemeyi kapatır (bkz. Bağlantı Güvenilirliği). IronFlock(), negatif bir değer, NaN veya sonsuz bir değer için ValueError, sayı olmayan bir değer için ise TypeError yükseltir

Veri Yayımlama

publishToTable / publish_to_table

Bir filo tablosuna veri kaydı yazar. Tablo adı, uygulamanızın data-template.yml dosyasında tanımlanan bir tabloyla eşleşmelidir. SDK, veriyi doğru proje veritabanına otomatik olarak yönlendirir.

appendToTable / append_to_table ile aynıdır: tablonun ekleme prosedürünü çağırır; bu yüzden bir platform yeniden başlatmasını atlatır — bağlantı için yeniden bağlanma penceresi boyunca bekler ve veri arka ucu tabloyu henüz sunmadığı sürece yeniden dener — ve veri arka ucu satırı reddettiğinde hata yükseltir (reddeder, bir hata döndürür). Platform yeniden başlarken hiçbir satır kaybolmaz.

Üç SDK’nın 1.9.1 ve önceki sürümleri satırı bunun yerine tablonun yazma konusuna yayımlıyordu: veri arka ucu yeniden başlarken yayımlanan bir satır kayboluyor, reddedilen bir satır ise hata vermeden düşürülüyordu. Artık böyle bir satır çağrıyı başarısız kılar — örneğin tsp içermeyen bir satır ya da veri şablonunda bulunmayan bir tablo (yeniden bağlanma penceresinden sonra).

from datetime import datetime, timezone await ironflock.publish_to_table("sensordata", { "tsp": datetime.now(timezone.utc).isoformat(), "temperature": 22.5, "humidity": 60, "device_id": "sensor-001" })

Veri arka ucu satırı ilk argümandan okur: Python’da bir dict, JavaScript’te dizinin ilk öğesi, Go’da ilk konumsal argüman (bir map veya bir struct). Ek anahtar kelime argümanları — Go’da argümanlar arasındaki bir ironflock.Kwargs değeri — yalnızca veri şablonunun onlara eşlediği sütunlar için okunur (kwargs.<name>).

Her satırın bir tsp’ye ihtiyacı vardır. Her tablonun zorunlu bir tsp sütunu vardır: satırın zaman damgası — ör. bir ISO 8601 dizesi ya da Go’da UTC’de RFC 3339 olarak gönderilen bir time.Time —; veri şablonu onu başka bir yere eşlemedikçe veri arka ucu bunu satırdan okur. tsp içermeyen bir satırı, appendToTable / append_to_table altında anlatıldığı gibi reddeder.

Varlık tablolarında kısmi satırlar. Varlık anahtarı olan bir tabloda (maintainLatestFlagFor) bir satır yalnızca varlık anahtarını, tsp’yi ve değişen sütunları taşıyabilir. Satırın dışarıda bıraktığı bir sütun varlığın önceki değerini korur; None / null / nil olarak gönderilen bir sütun temizlenir. Bir alanın dışarıda bırakılmış sayılıp sayılmayacağı satırı nasıl oluşturduğunuza bağlıdır:

  • Python: değeri None olan bir anahtar null olarak gönderilir ve sütunu temizler. Eski değeri korumak için anahtarı dict’ten kaldırın.
  • JavaScript: değeri undefined olan bir özellik veri yükünden düşer, bu yüzden eski değeri korur. Sütunu temizlemek için onu null yapın.
  • Go: omitempty veya omitzero etiketli bir struct alanı boş olduğunda dışarıda bırakılır, bu yüzden eski değeri korur. Aksi halde nil bir işaretçi alanı, bir ironflock.Row içindeki nil değer gibi, null olarak gönderilir ve sütunu temizler.

Aynısı dört yazma yönteminin tümü için geçerlidir. Varlık anahtarı olmayan bir tabloda, satırın dışarıda bıraktığı bir sütun NULL olarak saklanır.

appendToTable / append_to_table

Uzak prosedür çağrısı kullanarak filo tablosuna veri ekler: reddedilen bir satır bir hatadır. publishToTable / publish_to_table de aynısını yapar; tek fark, hata mesajının işleme verdiği addır.

result = await ironflock.append_to_table("sensordata", { "tsp": datetime.now(timezone.utc).isoformat(), "temperature": 22.5, "humidity": 60 })

Satırın, publishToTable’da olduğu gibi bir tsp’ye ihtiyacı vardır. Veri arka ucu tsp içermeyen bir satırı wamp.error.runtime_error ile ve bir neden belirtmeden reddeder; SDK’nın hatası bu durumda şunu ekler: “the data backend refused the row without a reason — a missing tsp is the usual cause; see the error-logs table”. Bir appliance’ta dolan disk gibi türü belirli retler Veri Arka Ucu Retleri altında listelenir.

publishRowsToTable / publish_rows_to_table

Bir filo tablosuna tek bir mesajda birden çok satır (toplu ekleme) yazar. Platform, tüm yığını tek bir işlemde atomik olarak (ya hep ya hiç) ekler. Satır başına bir gidiş-dönüşün çok maliyetli olacağı yüksek frekanslı veriler için bunu kullanın. appendRowsToTable / append_rows_to_table ile aynıdır: toplu ekleme prosedürünü çağırır, publishToTable gibi bir platform yeniden başlatmasını atlatır ve veri arka ucu yığını reddettiğinde başarısız olur.

await ironflock.publish_rows_to_table("sensordata", [ {"tsp": "2024-01-15T10:30:00.000Z", "temperature": 22.5}, {"tsp": "2024-01-15T10:30:01.000Z", "temperature": 22.7}, ])

İkinci argüman, her biri kendi tsp’sine sahip, eklenecek satır nesnelerinden oluşan boş olmayan bir listedir — Go’da bir satır slice’ı ([]ironflock.Row, []map[string]any veya bir struct slice’ı). Veri arka ucunun reddettiği bir yığın — örneğin bir satırın tsp’si eksik olduğu için — çağrıyı başarısız kılar ve yığının hiçbir satırı saklanmaz. (SDK’ların 1.9.1 ve önceki sürümleri yığını tablonun toplu (bulk) konusuna yayımlıyordu; reddedilen bir yığın orada hata vermeden düşürülüyordu.)

appendRowsToTable / append_rows_to_table

Bir filo tablosuna tek bir uzak prosedür çağrısında birden çok satır (toplu ekleme) ekler. Platform, tüm yığını atomik olarak (ya hep ya hiç) ekler: herhangi bir satır geçersizse tüm yığın reddedilir ve hiçbir şey kalıcı hale getirilmez. publishRowsToTable / publish_rows_to_table de aynısını yapar. Her satırın kendi tsp’sine ihtiyacı vardır; retler, nedensiz reddedilen bir yığın için verilen ipucu dahil, appendToTable ile aynıdır.

result = await ironflock.append_rows_to_table("sensordata", [ {"tsp": "2024-01-15T10:30:00.000Z", "temperature": 22.5}, {"tsp": "2024-01-15T10:30:01.000Z", "temperature": 22.7}, ]) # result -> {"success": True, "count": 2}

reportError / report_error

Bir uygulama hatasını filonuzun error-logs tablosuna raporlar. Bu, publishToTable / appendToTable üzerine kullanışlı bir sarmalayıcıdır: satırı source: "app", bir önem level değeri ve bir zaman damgasıyla işaretler, ardından onu herhangi bir normal tablo satırı gibi yazar. Hata, fleetdb sistem hatalarının kullandığı (source: "system" olarak etiketlenmiş) aynı error-logs tablosuna düşer; bu nedenle getHistory ile sorgulanabilir, subscribeToTable / subscribe_to_table ile akışa alınabilir, board-template’lerde kullanılabilir ve transformed.error-logs üzerinde gerçek zamanlı olarak teslim edilir — platformun sistem hatası bildirimini tetiklemeden.

# Writes a row to the error-logs table await ironflock.report_error("Sensor read timed out", level="warning") # Pass an exception to capture its traceback (falls back to the message) try: risky_operation() except Exception as err: await ironflock.report_error(err) # Show the operator a friendlier line than the raw error await ironflock.report_error( "Calibration failed: offset 0.42 out of range", user_message="Please recalibrate the sensor", )

Satır { tsp, msg, user_message, source: "app", level } biçimindedir: msg teknik metni (bir traceback ya da stack) tutar; user_message ise board’un hata bildiriminin (toast) gösterdiği metni: ilettiğiniz kullanıcı mesajını ya da, verilmediyse, mesajın kendisini.

Parametreler:

ParametreTürAçıklama
errorstr / string veya istisna / ErrorHata mesajı veya traceback/stack (ya da mesajı) kaydedilen bir istisna
levelstr / string, isteğe bağlıÖnem düzeyi: "error", "warning", "info" veya "debug"; panonun bildirim (toast) widget’ının gösterdiği türler bunlardır. Varsayılan "error". SDK 1.9.1 ve öncesinin yazımı olan "warn", "warning" olarak gönderilir
appendbool / boolean, isteğe bağlıUyumluluk için korunur: publishToTable ve appendToTable ikisi de ekleme yaptığından satır her durumda eklenir. Yalnızca hata mesajının ikisinden hangisini adlandıracağını seçer
tspstr / string, isteğe bağlıISO-8601 zaman damgası geçersiz kılması. Varsayılan olarak geçerli zaman
user_message / userMessagestr / string, isteğe bağlıOperatöre yönelik metin, user_message olarak saklanır. Varsayılan olarak kaydedilen mesaj

Python’da seçenekler anahtar kelime argümanlarıdır (report_error(error, level=..., append=..., tsp=..., user_message=...)); JavaScript’te bir seçenekler nesnesi aracılığıyla geçilir (reportError(error, { level, append, tsp, userMessage })); Go’da ise bir struct aracılığıyla (ReportError(ctx, errOrMsg, ironflock.ReportErrorOptions{Level, Append, Tsp, UserMessage})). Burada errOrMsg bir error veya bir dizedir, Level ironflock.LevelError, LevelWarning, LevelInfo, LevelDebug değerlerinden biridir ve döndürülen *Result ekleme sonucudur.

publish

Kendinize ait bir WAMP konusuna mesaj yayımlar. Veritabanı tablosuna eşlenmeyen özel mesajlaşma veya olaylar için bunu kullanın. Yönlendirici bazı adları platform için ayırır — bkz. Bir Uygulamanın Kullanabileceği URI’ler.

Tablo yazmaları gibi publish de cihaz meta verisini anahtar kelime argümanlarına ekler: DEVICE_SERIAL_NUMBER, DEVICE_KEY ve DEVICE_NAME. Bu adlardan birini taşıyan kendi anahtar kelime argümanınız önceliklidir.

Bağlantı yokken publish, bir bağlantı için yeniden bağlanma penceresi boyunca (varsayılan olarak 60 saniye, bkz. Bağlantı Güvenilirliği) bekler; böylece bir yayımlama kısa bir kesintiyi atlatır. Ardından bir kez gönderilir, asla yeniden denenmez. Yönlendirici, kimsenin abone olmadığı bir mesajı da onaylar; bu yüzden bu arada kapalı olan bir abone onu kaçırır.

await ironflock.publish("com.myapp.alerts", { "level": "warning", "message": "Temperature threshold exceeded" })

Geçmiş Veri Sorgulama

getHistory

Bir filo tablosundan veya transform’dan geçmiş verileri getirir: eşleşen en yeni satırları, artan tsp sırasıyla. Filtreleme, zaman aralığı ve sayfalama desteklenir.

# Simple query data = await ironflock.getHistory("sensordata", {"limit": 100}) # Query with time range and filters data = await ironflock.getHistory("sensordata", { "limit": 500, "offset": 0, "timeRange": ["2026-01-01T00:00:00Z", "2026-03-01T00:00:00Z"], "filterAnd": [ {"column": "temperature", "operator": ">", "value": 20}, {"column": "humidity", "operator": "<=", "value": 80} ] }) # Current value(s) only: the "latest" marker returns the newest row per entity current = await ironflock.getHistory("sensordata", { "limit": 100, "filterAnd": [{"latest": True}] }) # One field of a large json column: the column comes back pruned to its paths readings = await ironflock.getHistory("sensordata", { "limit": 100, "columns": ["json_data"], "columnPaths": ["json_data.sensor.temp"], })

Sorgu parametreleri:

AlanTürAçıklama
limitint / numberDöndürülecek maksimum satır sayısı (1–10.000, zorunlu; bir transform için 1–3.000)
offsetint / numberSayfalama için kaydırma
timeRangelist / array[start, end] — ISO tarih-saat dizeleri veya epoch milisaniye sayıları, asla karışık değil; açık bir uç için None / null. Eski bir {"start": ..., "end": ...} nesnesi bu ikiliye dönüştürülür
filterAndlist / arrayAND ile birleştirilen filtre girdileri: koşullar, gruplar ve/veya latest işareti (aşağıya bakın)
columnslist / arrayDöndürülecek sütunlar (isteğe bağlı). tsp, device_key ve authid her zaman dahil edilir; tüm sütunlar için bu alanı atlayın
columnPathslist / arrayjson sütunlarını budar (isteğe bağlı): filtrelerin kullandığı gösterimde JSON yolları ("json_data.a.b", "json_data['key']"). columns içinde listelenen bir json sütunu yalnızca yollarının birleşimini içerecek şekilde döner; burada yolu olmayan bir sütun bütün olarak döner. Transform’lar ve fleetdb v1.0.52’den eski veri arka uçları tarafından yok sayılır

Sorgu parametreleri geçtiğinizde limit zorunludur; hiç parametre geçmezseniz (Go’da nil), getHistory en yeni 10 satırı okur.

Go’da bunlar ironflock.TableQueryParams türünün Limit, Offset, TimeRange, FilterAnd, Columns ve ColumnPaths alanlarıdır. TimeRange bir *ironflock.TimeRange{Start, End} değeridir: her sınır bir time.Time, bir ISO 8601 dizesi, bir epoch milisaniye sayısı ya da açık bir uç için nil olabilir (ironflock.Between, Since ve Until, time.Time değerlerinden bir aralık oluşturur). FilterAnd bir []ironflock.Filter değeridir. Eski nesne biçimi yoktur.

Filtre operatörleri: =, !=, <>, >, <, >=, <=, LIKE, ILIKE, NOT LIKE, NOT ILIKE, IN, NOT IN, IS NULL, IS NOT NULL. JavaScript bu listeyi SQL_OPERATORS olarak dışa aktarır; Go’da ironflock.SQLOperators() onu döndürür.

Her filtre koşulu column, operator ve value anahtarlarına sahip bir nesnedir — Go’da ironflock.Where(column, operator, value), ironflock.IsNull(column) ve ironflock.IsNotNull(column) ile oluşturulur. Operatörler büyük/küçük harf fark etmeksizin, çevresindeki boşluklar yok sayılarak eşleştirilir ve yukarıda listelenen biçimde — veri arka ucunun kabul ettiği tek biçimde — gönderilir; böylece "like", gruplar içinde de "LIKE" olarak gider. Listenin dışındaki bir operatör, bir uyarıyla birlikte verildiği gibi gönderilir. IS NULL ve IS NOT NULL bir value almaz ve NULL’ı sorgulamanın tek yoludur: diğer her operatör, sütunu NULL olan bir satırı tam SQL’deki gibi dışarıda bırakır. IN ve NOT IN bir liste alır (Go’da bir slice). LIKE büyük/küçük harfe duyarlıdır; duyarsız eşleştirme için ILIKE kullanın.

OR ile birleştirme. filterAnd girdileri AND ile birleştirilir. Bir grup girdisi kendi girdilerini — koşulları, latest işaretini veya başka grupları — tek bir operatörle, "AND" ya da "OR" ile birleştirir:

# Rows that are not soft-deleted: deleted IS NULL OR deleted = false "filterAnd": [ { "combinator": "OR", "filters": [ {"column": "deleted", "operator": "IS NULL"}, {"column": "deleted", "operator": "=", "value": False}, ], } ]

Gruplardan önceki bir veri arka ucu (v1.2.0 öncesi fleetdb) bu yapının bir kısmını uygulamak yerine onu reddeder; böylece filtrenin dışarıda bıraktığı satırları sessizce döndürmek yerine açıkça başarısız olur.

Güncel değerleri okuma. filterAnd içindeki bir {"latest": true} girdisi (Go’da ironflock.Latest()) bir filtre koşulu değil, bir mod anahtarıdır: veri arka ucu yalnızca varlık başına en yeni satırı döndürür; bu satır, tablonun maintainLatestFlagFor ile bildirdiği varlık anahtarından SQL’de türetilir. Varlık anahtarı olmayan bir tablo, yalnızca en son tek satırını döndürür.

Diğer koşullar bu işaretle beklediğiniz gibi birleşir: varlık anahtarı sütunları üzerindeki koşullar hangi varlıkların döndürüleceğini daraltır; diğer tüm koşullar ve timeRange ise elde edilen en son satırlara uygulanır. Yani {"latest": true} ile bir deleted filtresini birleştirmek, silinen varlıkların önceki satırını yeniden ortaya çıkarmak yerine bu varlıkları gizler.

IronFlock’un önceki sürümleri fiziksel bir latest_flag sütunu saklıyordu. Bu sütun artık mevcut değil — eski bir latest_flag = true filtresi hâlâ kabul edilir ve bu işaret gibi ele alınır, ancak yeni kodlar {"latest": true} kullanmalıdır. latest işareti getSeriesHistory içinde kullanılamaz.

Zaman aralıkları. Veri arka ucu, dize olarak verilen bir sınırı JavaScript’in Date nesnesiyle okur; bu yüzden bir ISO 8601 tarihi veya tarih-saati yazın (2026-07-01, 2026-07-01T12:30:15.250Z) ve tarih ile saati T ile ayırın. SDK’lar, Date’in yanlış okuduğu 0–99 yıllarında tarih ile saat arasındaki boşluğu reddeder: "0001-01-01 00:00:00" — Python’da str(datetime.min) ifadesinin verdiği değer — 2001 olarak okunurdu. Python SDK’sı, datetime.fromisoformat ile okunamayan bir dizeyi de reddeder. Saat dilimi olmayan bir saat UTC olarak okunur. Sayısal bir sınır epoch milisaniyesidir ve sonlu olmalıdır: NaN ve ±Infinity veri arka ucuna açık bir sınır olarak ulaşır ve zaman filtresini sessizce düşürürdü; bu yüzden SDK’lar bunları göndermeden önce reddeder. Go’da bir time.Time sınırı UTC’de RFC 3339 olarak gönderilir; bir dize sınırı ise Date’in doğru okuduğu ISO 8601 biçimlerinden biri olmalıdır — bir tarih ya da isteğe bağlı bir Z veya UTC farkı (+02:00 veya +0200) içeren bir tarih ve günün saati; temel biçim 20260701T123000Z, yalnızca saatten oluşan bir fark veya ayda bulunmayan bir gün (2026-02-30) gibi diğer dizeler, hiçbir şey gönderilmeden önce ironflock.ErrInvalidArgument ile başarısız olur.

Transform’lar. Bir transform (bir veri şablonunun SQL görünümü, bkz. Dönüşüm Tabloları) bir tablodan farklı okunur. Veri arka ucu yalnızca limit — en fazla 3000; daha büyüğü URI_INVALID_LIMIT ile reddedilir —, offset ve filterAnd uygular. timeRange, columns, columnPaths ve latest işaretini yok sayar; transform’un tanımlamadığı bir sütun üzerindeki filtreyi düşürür (bir transform’un örtük tsp, device_key veya authid sütunu yoktur), bu da sonucu genişletir. Satırları, görünümün kendi sırasının tersiyle gelir: en yeni satırları en eskiden başlayarak yalnızca görünüm en yeniden başlayarak sıraladığında alırsınız. Bir transform’un zaman aralığını SQL’inde sınırlayın.

Büyük sonuçlar. Veri arka ucunun tek bir mesajına (8 MiB JSON) sığmayacak kadar büyük bir sonuç parçalar halinde gelir ve SDK bunları bellekte yeniden birleştirir: tek bir okumanın satırlarını aynı sırayla alırsınız. Tutmayan parçalar — biri eksik veya yinelenmiş ya da satır sayısı veri arka ucunun özetinden farklı — satırların bir kısmını döndürmek yerine okumayı başarısız kılar. 8 MiB’ı aşan tek bir satır veya veri arka ucunun 1 GiB korumasını aşan bir sonuç URI_RESULT_TOO_LARGE ile reddedilir: limit değerini düşürün, timeRange aralığını daraltın, daha az columns seçin veya columnPaths ile budayın.

getSeriesHistory / get_series_history

Bir filo tablosundan alt örneklenmiş zaman serisi verileri alır: zaman kovası başına toplanan sütunlar (ör. saatlik ortalamalar). Uzun zaman aralıklarını kapsayan grafikler için idealdir. Tablolar için (transform’lar için değil), fleetdb v1.0.58 ve sonrasındaki veri arka uçlarında kullanılabilir.

from datetime import datetime, timedelta, timezone from ironflock import SeriesMetric now = datetime.now(timezone.utc) avg = SeriesMetric(ref="temperature", method="AVG") # AVG, SUM, COUNT, MIN, MAX, FIRST, LAST series = await ironflock.get_series_history("sensordata", { "metrics": [avg, {"ref": "humidity", "method": "MAX"}], "bucketMs": 3_600_000, # one-hour buckets; omit to divide the range into `limit` buckets "limit": 24, # the bucket budget, 1–10000 "timeRange": [(now - timedelta(hours=24)).isoformat(), now.isoformat()], # required, with a start "groupBy": ["device_key"], }) for row in series: print(row["tsp"], row["device_key"], row[avg.column]) # avg.column is "AVG:temperature"

Sorgu parametreleri:

AlanTürAçıklama
metricslist / arrayKova başına hesaplanan toplamlar, en az bir tane: {"ref": ..., "method": ...}. ref bir sütun veya bir json sütununun içine giden bir JSON yoludur ("json_data.temp"); method ise "AVG", "SUM", "COUNT", "MIN", "MAX", "FIRST" veya "LAST" olur. Her metrik "<METHOD>:<ref>" adı altında döner ve bu ad 63 bayta sığmalıdır
bucketMsint / numberTam milisaniye cinsinden kova genişliği, en az 1000 (isteğe bağlı). Zaman aralığını limit kovaya bölmek için atlayın
limitint / numberKova bütçesi (1–10.000) — satır limiti değildir
timeRangelist / array[start, end] — ISO tarih-saat dizeleri veya epoch-ms sayıları. Zorunludur ve bir başlangıç içermelidir; bitiş olarak None / null şimdi anlamına gelir. Bitiş başlangıçtan sonra olmalıdır
groupBylist / arrayHer kovayı grup başına bir satıra bölen sütunlar (isteğe bağlı)
filterAndlist / arraygetHistory’deki gibi AND ile birleştirilen koşullar ve gruplar (isteğe bağlı). latest işareti burada, bir grup içinde de reddedilir; güncel değerleri okumak için getHistory kullanın

Satırlar. Her satır bir kovadır — groupBy ile, bir grubun kovası. tsp, kovanın epoch milisaniye cinsinden başlangıcıdır; her groupBy sütunu kendi adıyla, her metrik ise "<METHOD>:<ref>" altında döner (Python’da SeriesMetric.column, JavaScript’te seriesColumn(metric), Go’da SeriesMetric.Column()), ör. row["AVG:temperature"]. Satırlar tsp değerine göre artan sıradadır; satırı olmayan bir kova sonuçta yer almaz (boşluk doldurma yoktur). AVG ve SUM sayısal sütunları alır, MIN ve MAX dizeleri ve zaman damgalarını da; FIRST ve LAST kovanın en erken ve en geç satırının değerini verir; COUNT null olmayan değerleri sayar (tsp için: satırları). Büyük bir sonuç, getHistory’deki gibi parçalardan yeniden birleştirilir.

Kovalar ve açık bir uç. limit satırları değil kovaları sayar. bucketMs olmadan zaman aralığı limit kovaya bölünür. bucketMs verildiğinde, aralık limit değerinden fazla kova içeriyorsa veri arka ucu kovaları bucketMs değerinin bir katına genişletir — ve açık bir uç, veri arka ucunun kendi “şimdi”sine, yani sizinkinden biraz sonrasına kadar uzanır. Açık uçlu son 24 saat 25 adet bir saatlik kova içerir, bu yüzden limit: 24 iki saatlik kovalar alır. Örnekteki gibi bitişi sınırlayın veya bir kova fazlasına izin verin: bucketMs ve açık bir uçla limit + 1 kova dönebilir.

SDK’lar, veri arka ucunun reddedeceği şeyleri göndermeden önce denetler: en az bir metrik, boş olmayan ref’ler, bilinen metotlar, 63 baytı aşmayan sütun adları, bir başlangıç, başlangıçtan sonra gelen bir bitiş ve en az 1000 olan bir tamsayı olarak bucketMs (Go’da tam milisaniye cinsinden, en az 1 saniyelik bir Bucket). Veri arka ucu, yanıtlayamadığı şeyi URI_INVALID_TIME_RANGE, URI_INVALID_METRIC, URI_INVALID_GROUP_BY veya URI_SERIES_TOO_MANY_GROUPS (50.000’den fazla satır) ile reddeder — bkz. Veri Arka Ucu Retleri.

Kullanımdan kaldırılan biçim. 1.9.0’a kadarki SDK sürümleri metrics alanını sütun adları artı üst düzey bir method olarak gönderiyordu ({"metrics": ["temperature"], "method": "AVG", ...}); veri arka uçları bu biçimi fleetdb v1.0.58’den beri reddediyor. Bu biçim hâlâ çalışır: SDK sütun başına bir {ref, method} metriği gönderir, uyarır (Python’da bir DeprecationWarning, JavaScript’te süreç başına bir kez konsol uyarısı) ve sonuç sütunlarını yeniden sütun adlarıyla adlandırır; böylece eski kod row["temperature"] okumaya devam eder. Tek istisna, satırda o adda bir sütunun zaten bulunmasıdır; örneğin tsp’nin COUNT’u için tsp. {ref, method} metriklerine geçin ve row["AVG:temperature"] okuyun. Go SDK’sında yalnızca güncel biçim vardır: metrik başına bir metot (SeriesMetric).

Veriye Abone Olma

subscribeToTable / subscribe_to_table

Bir filo tablosundaki gerçek zamanlı güncellemelere abone olur. Veri arka ucu yeni bir satır sakladığında işleyici çağrılır; ilk argümanı, saklandığı haliyle satırdır — değerler veri şablonunun sütun türlerine göre tiplendirilmiş, gizli sütunlar maskelenmiş olarak. Toplu ekleme yolu (publishRowsToTable / appendRowsToTable) üzerinden yazılan satırlar işleyicinize birer birer teslim edilir, böylece verinin nasıl yazıldığından bağımsız olarak işleyici kodu aynı kalır.

def on_sensor_data(*args, **kwargs): row = args[0] print("New reading:", row["tsp"], row["temperature"]) await ironflock.subscribe_to_table("sensordata", on_sensor_data)

subscribeToTable / subscribe_to_table, iki beslemenin de tanıtıcısı olan bir TableSubscription döndürür: onun unsubscribe() metodu iki beslemeyi de kaldırır ve aşağıda açıklanan kaçırılan satırların teslimini sona erdirir (bkz. unsubscribe / unregister).

Bağlantı kopukken saklanan satırlar, yeniden bağlanmanın ardından gelir. Yönlendirici, bağlantı kopukken yayımlananları yeniden göndermez; bu yüzden SDK her yeniden bağlanmadan sonra bu arada saklanan satırları okur ve bunları, canlı gelen satırlardan önce, en eskiden başlayarak işleyicinize teslim eder: tsp değeri işleyicinizin aldığı en yeni satırınkinden daha geç olan her satırı. İşleyiciniz henüz hiç satır almadıysa başlangıç noktası, abone olduğunuz anda saklanmış en yeni satırdır: SDK bu satırı abone olduktan hemen sonra okur; bu okuma başarısız olursa abone olduğunuz andan (cihazın saatine göre) başlar; o sırada boş olan bir tablo en baştan okunur. Bu arada daha eski bir tsp ile yazılan bir satır (örneğin bir cihazın arabelleğe aldığı ölçümleri göndermesi) sonradan teslim edilmez. Kaçırılan satırların tek bir teslimi en fazla en yeni 10.000 satırı kapsar ve bu kadar satır okunduğunda günlüğe bir uyarı kaydedilir. Kaçırılan satırları getiren okuma, her geçmiş okuması gibi en fazla yeniden bağlanma penceresi süresince veri arka ucunu bekler ve canlı satırlar da bu okumayı bekler; okuma başarısız olursa bu arada saklanan satırlar teslim edilmez ve günlüğe bir uyarı kaydedilir. Kaçırılan satırlar olaylardan değil bir okumadan geldiği için işleyici her birini olay ayrıntıları olmadan alır: Python’da yalnızca satırı, JavaScript’te ([row], {}) biçiminde, Go’da ise Topic ve Args içeren ve aboneliğin DeliveryGroup’unda sırayla teslim edilen bir Event olarak. Kaçırılan satırların teslimi SDK’da 1.10.0 sürümünden itibaren bulunur.

Bir transform’un kendine ait satırları yoktur: zamanlamasının her tetiklenişinde veri arka ucu görünümün tamamını — en fazla 3000 satır, görünümün sırasının tersiyle — ilk argümanı satır listesi olan tek bir olay olarak yayımlar. Bir transform’un kaçırılan satırların teslimine ihtiyacı yoktur: yeniden bağlanmanın ardından gelen bir sonraki tetiklenişi, görünümün tamamını yeniden yayımlar. Python’da event_rows(args[0]), JavaScript’te eventRows(args) ve Go’da ev.Rows() her iki biçimi de okur: bir tablonun satırı [row] verir, bir transform’un listesi listenin kendisini (boş bir görünüm için []), başka her şey ise None / undefined / nil verir. Go’da bir transform olayı için ev.Row() nil’dir.

from ironflock import event_rows def on_hourly(*args, **kwargs): for row in event_rows(args[0]) or []: print(row) await ironflock.subscribe_to_table("hourly_averages", on_hourly)

subscribe

Özel gerçek zamanlı mesajlaşma için kendinize ait bir WAMP konusuna abone olur. Tablo satırları için subscribeToTable / subscribe_to_table kullanın: yönlendirici, ham tablo yazma konularına yapılan abonelikleri reddeder (bkz. Bir Uygulamanın Kullanabileceği URI’ler).

def on_alert(*args, **kwargs): print("Alert received:", args, kwargs) alerts = await ironflock.subscribe("com.myapp.alerts", on_alert) # Later: the handler is called for no further event await alerts.unsubscribe()

subscribe, aboneliğin tanıtıcısı olan bir Subscription döndürür (bkz. unsubscribe / unregister). Her çağrı, zaten abone olunmuş bir konu için de kendine ait bir tanıtıcı döndürür.

Bağlantı yokken subscribe, publish gibi bir bağlantı için yeniden bağlanma penceresi boyunca (varsayılan olarak 60 saniye) bekler; subscribeToTable / subscribe_to_table de öyle (bkz. Bağlantı Güvenilirliği).

Konu birebir eşleştirilir. İşleyiciden sonra verilen isteğe bağlı bir argüman olan abonelik seçenekleri bunu değiştirebilir: "prefix" değerinde bir match, verilen konuyla başlayan her konuya abone olur. Seçenekler Python’da autobahn’ın SubscribeOptions sınıfıdır (SubscribeOptions(match="prefix"), autobahn.wamp.types içinden), JavaScript’te bir nesnedir ({ match: "prefix" }), Go’da ise ironflock.SubscribeOptions{Match: "prefix"}. Abonelik her yeniden bağlanmadan sonra aynı seçeneklerle geri yüklenir. subscribeToTable / subscribe_to_table aynı seçenekleri alır ve iki beslemesine de bunlarla abone olur.

unsubscribe / unregister

subscribe, subscribeToTable / subscribe_to_table ve registerDeviceFunction / register_device_function her biri bir tanıtıcı döndürür. Bir tanıtıcı, siz onu kaldırana kadar yeniden bağlanmalar boyunca geçerli kalır: SDK, tanıtıcının temsil ettiği şeyi her yeniden bağlanmadan sonra geri yükler.

TanıtıcıDöndürenÜyeler
Subscriptionsubscribeunsubscribe(), topic, active
TableSubscriptionKendi uygulamanızın ve tüketilen bir uygulamanın subscribeToTable / subscribe_to_table metoduunsubscribe(), table, active
RegistrationregisterDeviceFunction / register_device_function ve takma adlarıunregister(), procedure, active

topic, table ve procedure, tanıtıcının temsil ettiği şeyi adlandırır; procedure tam WAMP URI’sidir. active, aboneliğin veya kaydın şu anda yönlendiricide etkin olup olmadığını söyler: bağlantı kopukken, başarısız bir geri yüklemeden sonra bir yeniden deneme başarılı olana kadar ve tanıtıcı kaldırıldıktan sonra false olur. Bir TableSubscription, iki beslemesi de etkin olduğu sürece etkindir. ironflock.unsubscribe(handle) bir Subscription veya bir TableSubscription, ironflock.unregister(registration) ise bir Registration alır; her biri, tanıtıcının kendi metoduyla aynı işi yapar.

status = await ironflock.subscribe("com.myapp.status", on_status) readings = await ironflock.subscribe_to_table("sensordata", on_row) add = await ironflock.register_device_function("com.myapp.add", add_numbers) print(readings.table, readings.active) # sensordata True await status.unsubscribe() # the same as: await ironflock.unsubscribe(status) await ironflock.unsubscribe(readings) # both feeds of the table, and its catch-up await ironflock.unregister(add) # the same as: await add.unregister()

unsubscribe() ve unregister(), çağrıldıkları anda etki eder ve bir awaitable döndürür: yönlendiricinin yanıt verdiğini bilmek için onu await edin; bir ret orada yükseltilir. async olmayan düz bir fonksiyon olan bir işleyici, subscription.unsubscribe() metodunu await etmeden çağırabilir. Üç tanıtıcı sınıfı ironflock paketinden dışa aktarılır.

Bir kaldırma işlemi üç SDK’da da aynı kurallara uyar:

  • Hemen etkili olur. İşleyici artık hiçbir olay için çağrılmaz: ne hâlâ kuyrukta bekleyen bir olay için, ne bir toplu eklemenin kalan satırları için, ne de kaçırılan satırların teslimiyle gelecek satırlar için. Kaldırılan bir fonksiyon artık çağrılmaz; yönlendiricinin kaydı düşürmeden önce hâlâ ona yönlendirdiği bir çağrı wamp.error.no_such_procedure ile reddedilir. Hâlihazırda süren bir çağrı beklenmez; bu yüzden bir işleyici kendi aboneliğini kaldırabilir. Kaldırdığınız şey bir yeniden bağlanmadan sonra asla geri yüklenmez.
  • Bir bağlantıyı beklemez. Bağlantı kopukken abonelik veya kayıt yerel olarak kaldırılır, çünkü yönlendirici onu oturumla birlikte düşürmüştür; çağrı da hemen döner. Bağlantı açıkken yönlendiriciye bildirilir ve çağrı, yönlendirici yanıt verdiğinde tamamlanır. Bir ret yükseltilir (Python, bir RuntimeError), fırlatılır (JavaScript, bir WampError) ya da döndürülür (Go), ancak kaldırma yine de geçerli kalır.
  • İdempotenttir. İkinci bir çağrı hiçbir şey yapmaz; tanıtıcı olmadan yapılan bir çağrı da (None, null veya undefined, nil) öyle. stop() / Stop sonrasındaki bir çağrı, aboneliği veya kaydı yalnızca yerel olarak kaldırır: Python ve JavaScript’te bir sonraki start() onu bu durumda geri yüklemez.
  • Tanıtıcılar birbirinden bağımsızdır. Bir tanıtıcıyı kaldırmak, aynı konu veya tablo üzerinde olsa bile, başka bir tanıtıcının işleyicisini asla kaldırmaz. Yönlendiricideki abonelik, konusunun son tanıtıcısıyla birlikte sona erer.
  • Bir TableSubscription iki beslemesini de kaldırır: transformed.<table> ve transformed.bulk.<table>; ayrıca kaçırılan satırların teslimini sona erdirir.

Yükseltme: 1.10.0 sürümünden önce Python ve JavaScript SDK’ları autobahn’ın abonelik ve kayıt nesnelerini döndürüyordu; subscribe_to_table / subscribeToTable ise yalnızca satır beslemesinin aboneliğini döndürüyordu, bu yüzden onu kaldırmak toplu beslemeyi abone hâlde bırakıyordu. Döndürülen değer üzerinde unsubscribe() veya unregister() çağıran kod çalışmaya devam eder ve kaldırdığı şey artık bir yeniden bağlanmadan sonra geri yüklenmez. id gibi, autobahn nesnelerinin diğer üyeleri artık yoktur.

Gizli Sütunlar

Uygulamanın veri şablonunda secret: true olarak bildirilen bir sütun şifrelenmiş olarak saklanır. Hiçbir olağan okuma yolu düz metni döndürmez, onu yazan uygulamaya bile:

Okuma yoluBir gizli sütunun görünümü
getHistory, subscribeToTable / subscribe_to_table ve tüketilen bir uygulamanın okumaları (panoların da kullandığı geçmiş okumaları ve gerçek zamanlı satırlar)SECRET_PLACEHOLDER olarak dışa aktarılan __secret__ yer tutucusu (Go’da ironflock.SecretPlaceholder)
SQL (SQL sorgu konsolu, veri dışa aktarımları ve FleetDB Access Postgres oturumu) ve veritabanı yedeklerisaklanan şifreli metin, ifsec:1:…
revealSecrets / reveal_secretsşifresi çözülmüş düz metin

NULL, her yolda NULL olarak geçirilir; böylece “atanmış ama gizli” ile “hiç yazılmamış” birbirinden ayırt edilebilir kalır.

Bir varlık tablosunda oku-değiştir-yaz güvenlidir: hâlâ __secret__ yer tutucusunu taşıyan bir satırı yeniden yayımlamak — ya da gizli sütunu tamamen atlamak — saklanan sırrın üzerine yazmak yerine onu korur; açıkça gönderilen null ise sırrı temizler. Kesin kurallar için veri arka ucu kılavuzundaki Gizli Sütunlar bölümüne bakın.

Yalnızca string türünde bir sütun gizli olabilir; ne tsp ne de bir varlık anahtarı gizli olabilir. Veri arka ucu her değeri AES-256-GCM ve o değere ait rastgele bir IV ile şifreler; bu yüzden aynı sır her satırda farklı bir şifreli metin olarak saklanır: gizli bir sütun filtrelenemez, gruplanamaz veya sıralanamaz. Böyle bir sütun üzerindeki filtre URI_SECRET_COLUMN ile reddedilir; bir değeri karşılaştırmak için verifySecret kullanın.

from datetime import datetime, timezone # Written like any other column — the data backend encrypts it on insert await ironflock.publish_to_table("credentials", { "tsp": datetime.now(timezone.utc).isoformat(), "device_id": "d-1", "api_token": "hunter2", }) # A normal read redacts it rows = await ironflock.getHistory("credentials", {"limit": 1}) # [{"tsp": "...", "device_id": "d-1", "api_token": "__secret__"}]

Aşağıdaki iki fonksiyon yalnızca uygulamanın kendi kapsayıcılarından çağrılabilir. Mesaj yönlendiricisi bunları her tarayıcı rolüne ve tüketen uygulamalara reddeder; bir ConsumedApp tanıtıcısının bunların karşılığını sunmamasının nedeni de budur: başka bir uygulamanın gizli sütunları size sansürlenmiş olarak ulaşır ve öyle kalır.

revealSecrets / reveal_secrets

Kendi tablolarınızdan birinin satırlarını, gizli sütunlarının şifresi çözülmüş halde okur.

rows = await ironflock.reveal_secrets("credentials", { "limit": 1, "filterAnd": [{"column": "device_id", "operator": "=", "value": "d-1"}], }) # [{"tsp": "...", "device_id": "d-1", "api_token": "hunter2"}]

Sorgu parametreleri getHistory ile aynıdır; ancak limit, 100’ü aşamaz. Bu üst sınır, tek bir çağrının koca bir tablonun şifresini çözmesini engellemek için vardır ve veri arka ucu daha büyük bir değeri sessizce kırpmak yerine reddeder. Sorgu parametreleri verilmezse çağrı en yeni 10 satırı okur. getHistory’den farklı olarak satırları en yeniden başlayarak döndürür.

Veri arka ucu, bir cihazdaki uygulama kimlik bilgisi başına dakikada en fazla 30 açığa çıkarma isteğini yanıtlar; bunun ötesinde çağrı URI_RATE_LIMITED ile başarısız olur. Bir sırrı her kullanımda değil, bir kez açığa çıkarın ve saklayın. Bir gizli sütun üzerindeki filtre URI_SECRET_COLUMN ile reddedilir. Veri arka ucu bu fonksiyonu yalnızca gizli sütun tanımlayan tablolar için sunar: diğer her tablo için yönlendirici wamp.error.no_such_procedure yanıtını verir; SDK bunu yeniden bağlanma penceresi boyunca yeniden dener ve ardından çağrı, prosedürün kayıtlı olmadığını belirten bir hatayla başarısız olur. Hata, en olası olanı başta olmak üzere nedenleri sıralar: tablo hiçbir gizli sütun tanımlamıyordur (veri şablonunda secret: true), tablo tanımlanmamıştır ya da veri arka ucu gizli sütunlardan önceki bir sürümdür.

verifySecret / verify_secret

Bir aday değeri, gizli sütunu ifşa etmeden onunla karşılaştırır — açığa çıkarma fonksiyonunun parola denetimi karşılığıdır. Karşılaştırma veri arka ucunun içinde, sabit zamanda çalışır ve geriye yalnızca yanıt döner.

ok = await ironflock.verify_secret( "credentials", "api_token", submitted_token, {"limit": 1, "filterAnd": [{"column": "device_id", "operator": "=", "value": "d-1"}]}, ) if ok: ...

Parametreler:

ParametreTürAçıklama
tablenamestr / stringKarşılaştırmanın yapılacağı tablo
columnstr / stringKarşılaştırılacak gizli sütun
candidatestr / stringSınanan düz metin. Sunucu tarafında karşılaştırılır ve asla tabloya yazılmaz
query_params / queryParamsSecretQueryParamsHangi satırların dahil olacağı. Varsayılan olarak en son satır; limit 100’ü aşamaz

Go’da parametreler context’ten sonra gelen konumsal dizelerdir; sorgu ise bir *ironflock.TableQueryParams değeridir (en son satır için nil).

JavaScript { match, checked } döndürür, Go ise Match ve Checked alanlarına sahip bir *ironflock.SecretVerifyResult; Python düz bir bool döndürür. checked elinizde olduğunda bunu kullanmaya değer: yanlış bir adayı (checked > 0), hiçbir satırla eşleşmeyen bir seçiciden (checked === 0) ayırır — bunlar kullanıcıya bildirilmesi gereken birbirinden çok farklı hatalardır.

Her satır kendi rastgele değeriyle şifrelendiği için, aynı sırrı tutan iki satır farklı şifreli metin saklar. Bir gizli sütun üzerinde = filtresinin çalışamamasının — veri arka ucu böyle bir sütun üzerindeki her filtreyi URI_SECRET_COLUMN ile reddeder — ve bunun yerine bu fonksiyonun var olmasının nedeni budur.

Veri arka ucu, bir cihazdaki uygulama kimlik bilgisi başına dakikada en fazla 120 denetimi yanıtlar; bunun ötesinde çağrı URI_RATE_LIMITED ile başarısız olur. Her istekte yapılan bir denetim için (ör. bir API anahtarı) olumlu bir sonucu kısa süreliğine önbelleğe alın. Gizli sütun olmayan bir sütun URI_NOT_A_SECRET_COLUMN ile reddedilir; hiç gizli sütunu olmayan bir tabloda ise çağrı, revealSecrets / reveal_secrets çağrısının orada başarısız olduğu gibi başarısız olur.

Uygulamalar Arası Veri Erişimi

Başka bir uygulamanın filo verilerini, aynı proje içinde kendi uygulamanızın içinden okuyun. Uygulamanız, sağlayıcı uygulamayı kendi data-template.yml dosyasının consumes: bölümünde belirtmeli (veya aşağıda açıklanan joker karakter iznine sahip olmalı) ve proje kullanıcısı erişim izni vermelidir. Erişim salt okunurdur: sağlayıcının paylaştığı tabloların ve transform’ların geçmişini sorgulayabilir ve satırlarına gerçek zamanlı olarak abone olabilirsiniz, ancak bunlara yazamazsınız. Tüketilen uygulamalara yapılan bağlantılar uygulama ve aşama başına önbelleğe alınır ve örneğiniz durduğunda otomatik olarak kapatılır.

Bağlantı, cihaz ajanının enjekte ettiği uygulama başına kimlik bilgisini (APP_AUTH_ID, APP_AUTH_SECRET) gerektirir. Platform, eski cihaz kimlik bilgisini — uygulama başına kimlik bilgisi almamış bir uygulamanın, ör. eski bir cihaz ajanı altında, geri dönüş olarak kullandığı seri numarasını — başka bir uygulamanın realm’inde reddeder (NOT_AUTHORIZED, bunu belirten bir mesajla). Sağlayıcı uygulama aynı cihazda çalışıyorsa durum farklıdır: bu kimlik bilgisi o uygulamanın realm’ine salt okunur olarak değil, o uygulamanın kendi tam yetkileriyle katılır.

Uygulamanız joker karakter (wildcard) iznine (consumes: [{ app: "*" }]) sahipse, sağlayıcıları listConsumableApps / list_consumable_apps ve connectToAllApps / connect_to_all_apps (aşağıda) ile dinamik olarak keşfedebilir ve açabilirsiniz.

connectToApp / connect_to_app

Başka bir uygulamanın veri arka ucuna salt okunur bir bağlantı açar ve bir tanıtıcı (handle) döndürür. Tanıtıcı getHistory / get_history, subscribeToTable / subscribe_to_table ve getSeriesHistory / get_series_history (yalnızca tablolar) işlevlerini sunar — kendi tablolarınızda kullandığınız sorgulama ve abone olma işlemlerinin aynısı, aynı parametreler ve sonuçlarla — ayrıca close ile paylaşılan tables / transforms kataloglarını da sağlar. Tanıtıcının subscribeToTable / subscribe_to_table metodu, kendi tablolarınızdakiyle aynı TableSubscription tanıtıcısını döndürür; ironflock.unsubscribe de bunu kabul eder (bkz. unsubscribe / unregister). Bu tablo abonelikleri de yeniden bağlanmanın ardından kaçırılan satırları aynı şekilde alır (bkz. subscribeToTable).

Tanıtıcı ayrıca sağlayıcının adını ve aşamasını (app ve stage, Go’da App ve Stage) ve sağlayıcının realm’ine olan bağlantısını taşır: is_connected / isConnected / IsConnected() bağlantının açık olup olmadığını söyler, connection / Connection() ise bağlantının kendisidir. JavaScript’te close(), bağlantı kapandığında, en geç 5 saniye içinde çözülür (resolve).

# Open a read-only handle on another app's data backend weather = await ironflock.connect_to_app("weather-app") # Inspect what the provider shares print([t["tablename"] for t in weather.tables]) # Query history and subscribe, just like your own tables rows = await weather.get_history("forecasts", {"limit": 100}) def on_forecast(*args, **kwargs): print("New forecast:", args) await weather.subscribe_to_table("forecasts", on_forecast)

Parametreler:

ParametreTürAçıklama
app_name / appNamestr / stringconsumes: bölümünüzde belirtildiği gibi sağlayıcı uygulamanın adı
stagestr / string, isteğe bağlıSağlayıcı aşaması (stage): "dev" veya "prod". Varsayılan olarak kendi uygulamanızın aşaması
on_error / onErrorcallable, isteğe bağlıAçık bağlantı kalıcı olarak reddedildiğinde (ör. izin daha sonra iptal edildiğinde — bir reddin ne zaman kesin sayıldığı için aşağıya bakın) bir CrossAppAccessError ile çağrılır

Erişim reddedilir veya yanlış kullanılırsa, code alanına (Go’da ironflock.CodeNoGrant gibi sabitlerle birlikte Code) sahip bir CrossAppAccessError yükseltilir (Python) / fırlatılır (JavaScript) / döndürülür (Go; errors.As ile sınanacak bir *ironflock.CrossAppAccessError): NO_GRANT, PROVIDER_NOT_INSTALLED, UNKNOWN_APP, PRIVATE_TABLE, SECRET_COLUMN (sağlayıcının gizli olarak işaretlediği bir sütuna — bir grup içinde de — filtre uygulayan veya o sütunu seçen bir sorgu) ya da NOT_AUTHORIZED (izin iptal edildi veya o anda doğrulanamadı — ya da uygulamanız eski cihaz kimlik bilgisini sundu; bu durumda mesaj bunu belirtir). Sağlayıcının yönlendiricisinin reddettiği (wamp.error.not_authorized, wamp.error.authorization_failed veya wamp.error.authentication_failed), tüketilen bir uygulamaya ait bir subscribeToTable / subscribe_to_table çağrısı da, reddedilen bir okuma gibi, NOT_AUTHORIZED koduna sahip bir CrossAppAccessError ile başarısız olur.

connectToApp / connect_to_app beklerken gelen bir ret, çağrıyı hemen başarısız kılar. Bir tanıtıcı açıldıktan sonra ret ancak kalıcı olduğunda kesin sayılır — bağlantının en son ayakta olduğu andan bu yana 3 veya daha fazla ret (yönlendiricinin oturumu bir kimlik doğrulama nedeniyle kapatması da, reddedilen her yeniden bağlanma da bir ret sayılır), ilki en az 60 saniye önce —, çünkü platform erişimi kısa bir süre doğrulayamadığında da aynı şekilde reddeder. O zamana kadar tanıtıcı yeniden bağlanmayı sürdürür ve bir yeniden bağlanma başarılı olursa toparlanır. Ret kesinleştiğinde on_error / onError / OnError çağrılır ve tanıtıcı önbellekten çıkarılır: bir sonraki connectToApp / connect_to_app / ConnectToApp yeni bir bağlantı açar. O andan itibaren tanıtıcının okumaları ve abonelikleri, on_error / onError hangi hatayla çağrıldıysa o hatayla hemen başarısız olur — Go’da wamp.ErrStopped’u saran bir hatayla.

Python’da stage ve on_error anahtar kelime argümanlarıdır; JavaScript’te bir seçenekler nesnesi aracılığıyla geçilir (connectToApp(appName, { stage, onError })); Go’da ise bir struct aracılığıyla (ConnectToApp(ctx, appName, ironflock.ConnectToAppOptions{Stage, OnError})); burada OnError bir func(*ironflock.CrossAppAccessError)’dır. Go’da ctx yalnızca çağıranın beklemesini sınırlar: aynı uygulama için eşzamanlı çağrılar tek bir denemeyi paylaşır ve Close(ctx) bir tanıtıcıyı kapatır. Go, uygulama adlarını büyük/küçük harf fark etmeksizin eşleştirir; ConsumedApp.Stage ise ifl.Stage() değerinin aksine küçük harfli aşamadır ("dev" veya "prod").

listConsumableApps / list_consumable_apps

Projedeki her özel olmayan sağlayıcıyı listeler — bu, joker karakter tüketim iznine (data-template.yml dosyanızdaki consumes: [{ app: "*" }], proje kullanıcısı tarafından verilir) sahip uygulamalar için temel keşif işlevidir. Tek bir çağrı yapar ve hiçbir bağlantı açmaz: döndürülen katalogları bir seçicide gösterin, ardından istediğiniz sağlayıcılar için connectToApp / connect_to_app çağırın — veya hepsini tek seferde açmak için connectToAllApps / connect_to_all_apps çağırın.

Not: İzni uygulamanızın data-template.yml dosyasında belirtin ve * işaretini tırnak içine alın — tırnaksız bir *, bir YAML takma adıdır ve ayrıştırılamaz:

consumes: - app: "*"
providers = await ironflock.list_consumable_apps() for p in providers: print(p["app"], list(p["stages"].keys())) # e.g. "weather-app" ["dev", "prod"]

Her giriş bir sağlayıcıyı tanımlar:

AlanTürAçıklama
appstr / stringSağlayıcı uygulama adı
provider_app_keyint / numberSağlayıcının uygulama anahtarı
stagesdict / objectAşama başına katalog { dev?, prod? }; bir aşama yalnızca sağlayıcının o aşama için bir veri arka ucu varsa mevcuttur. Her katalog, paylaştığı özel olmayan tables ve transforms öğelerini içerir

Go’da her girdi; App, ProviderAppKey ve Stages.Dev / Stages.Prod (Tables ve Transforms içeren bir *StageCatalog, eksik bir aşama için nil) alanlarına sahip bir ironflock.ConsumedAppInfo’dur; Catalog(stage) adıyla birini döndürür.

Uygulamanızın hiçbir joker karakter izni yoksa, code: NO_GRANT içeren bir CrossAppAccessError yükseltilir (Python) / fırlatılır (JavaScript) / döndürülür (Go).

connectToAllApps / connect_to_all_apps

Projedeki her özel olmayan sağlayıcıya tek bir çağrıda salt okunur tanıtıcılar (handle) açar (yalnızca joker karakter tüketicileri). Sağlayıcıları listConsumableApps / list_consumable_apps aracılığıyla numaralandırır ve her birini açar; istenen aşama için veri arka ucu bulunmayanları atlar. Her tanıtıcı, connectToApp / connect_to_app ile aynı anahtar altında önbelleğe alınır, böylece daha sonraki bir connectToApp(name) çağrısı zaten hazırlanmış tanıtıcıyı döndürür. Döndürülen tanıtıcılar, örneğiniz durduğunda birlikte kapatılır.

apps = await ironflock.connect_to_all_apps( on_error=lambda err: print("Provider skipped:", err) ) for app in apps: rows = await app.get_history(app.tables[0]["tablename"], {"limit": 10}) print(app.app, rows)

Parametreler:

ParametreTürAçıklama
stagestr / string, isteğe bağlıSağlayıcı aşaması (stage): "dev" veya "prod". Varsayılan olarak kendi uygulamanızın aşaması
continue_on_error / continueOnErrorbool / boolean, isteğe bağlıtrue olduğunda (varsayılan), açılamayan bir sağlayıcı on_error / onError’a bildirilir ve sonuçtan çıkarılır. false olduğunda, ilk hata yükseltilir/fırlatılır
on_error / onErrorcallable, isteğe bağlıAçılamayan her sağlayıcının hatasıyla çağrılır (continue_on_error / continueOnError true iken) ve zaten açılmış bir bağlantı daha sonra kalıcı olarak reddedilirse (ör. izin iptal edilirse) bir CrossAppAccessError ile çağrılır

Başarıyla açılan sağlayıcı tanıtıcılarını döndürür (connectToApp / connect_to_app ile aynı tanıtıcı türü). Uygulamanızın hiçbir joker karakter izni yoksa, code: NO_GRANT içeren bir CrossAppAccessError yükseltilir (Python) / fırlatılır (JavaScript) / döndürülür (Go).

Python’da stage, on_error ve continue_on_error anahtar kelime argümanlarıdır; JavaScript’te bir seçenekler nesnesi aracılığıyla geçilir (connectToAllApps({ stage, onError, continueOnError })); Go’da ise bir struct aracılığıyla (ConnectToAllApps(ctx, ironflock.ConnectToAllAppsOptions{Stage, OnError, StopOnError})); burada OnError bir func(error)’dır ve StopOnError: true, continueOnError: false’a karşılık gelir.

Yönetilen Dosya Depolama

Her uygulama veri arka ucu, tablolarının yanı sıra files özelliği (Go’da ifl.Files(), bir *filestore.FileStore) üzerinden erişilen özel bir nesne depolama alanı edinir. Bu özellik hiçbir G/Ç (I/O) işlemi yapmaz; bu yüzden üç SDK’nın hepsinde bağlantı başlatılmadan önce de okunabilir. Bunu görüntüler, PDF’ler, kamera kareleri, firmware blob’ları — kısacası bir tablo satırına ait olmayan her şey — için kullanın. Kurulum gerekmez: veri şablonunda files: bölümü bulunmayan bir uygulama bile default adında bir ad alanı edinir (kendi ad alanlarını tanımlayan bir şablon onun yerini alır — bkz. Ad Alanları).

Bu bölüm istemci tarafı referansıdır. Platform tarafı için — ad alanlarını, kotaları ve saklamayı tanımlama, uygulamalar arasında dosya paylaşma, uygulama başına S3 kimlik bilgileri ve yerinde (on-premises) davranış — bkz. Dosya Depolama.

Temel fikir şudur: bir nesneyi sakladığınızda size aynı çağrıda doğrudan bir tablo sütununa yazabileceğiniz kalıcı bir URL döner; böylece bir pano widget’ı onu başka hiçbir iş yapmadan görüntüleyebilir:

from datetime import datetime, timezone # Store an object and get a permanent URL back in the same call info = await ironflock.files.put("part-1.jpg", jpeg_bytes, content_type="image/jpeg") # The URL is safe to store in a table column — a dashboard widget can then # render <img src="{{photo_url}}"> without any extra round trip await ironflock.publish_to_table("inspections", { "tsp": datetime.now(timezone.utc).isoformat(), "part_id": "1", "photo_url": info.url, }) # Read it back data = await ironflock.files.get("part-1.jpg") # Every object in the folder 2026/, in its subfolders too (pages are fetched for you) async for obj in ironflock.files.iter(prefix="2026/"): print(obj.key, obj.size)

Bu URL hiçbir zaman sona ermez, ancak herkese açık bir bağlantı değildir: yalnızca bu veri arka ucu üzerinde READ erişimine sahip, kimliği doğrulanmış bir istek sahibi tarafından okunabilir kalır ve bir kimlik doğrulama proxy’si bunu her istekte denetler; kararını en fazla 5 dakika boyunca önbellekte tutar. Bu nedenle veritabanında saklanması güvenlidir.

Ad Alanları

Bir ad alanı (namespace), politika taşıyan bir anahtar önekidir — saklama süresi, paylaşım kuralları, izin verilen içerik türleri. Ayrı bir bucket değildir; bir uygulamanın her ad alanı, o uygulamanın tek depolama alanının içinde yer alır. Yalnızca bir nesne kümesinin farklı kurallara ihtiyacı olduğunda yeni bir tane tanımlayın; aksi halde default içinde kalın ve nesnelerinizi 2026/03/part-1.jpg gibi anahtar yollarıyla düzenleyin.

Ad alanlarını data-template.yml dosyasında tanımlayın. Herhangi birini tanımlamak örtük default’un yerini alır: default adında bir tane de listeleyin, aksi halde ad alanı belirtilmeyen her çağrı NO_SUCH_NAMESPACE ile başarısız olur.

files: # Storage budget the app suggests for itself. The project user can change it, # and their setting is the one that gets enforced. quotaBytes: 5368709120 namespaces: # Keep default: declaring namespaces replaces the implicit one. - name: default - name: frames description: Raw camera frames, one JPEG per inspected part. contentTypes: ["image/jpeg"] maxObjectBytes: 20971520 retention: { deleteAfter: 30 days }

Bütçenin ad alanı başına değil, uygulamanın tamamı için bir kez tanımlandığına dikkat edin. Bir ad alanı yalnızca uygulamanın tek depolama alanı içindeki bir anahtar önekidir, dolayısıyla önek başına bir bütçenin uygulanabileceği bir şey yoktur. maxObjectBytes ise ad alanı başınadır — bir toplamı değil, tek bir nesneyi sınırlar: ayarlanmadıysa 100 MiB, en fazla 5 GiB (üstünde OBJECT_TOO_LARGE).

Aşağıdaki her metot ad alanını isteğe bağlı bir argüman olarak alır ve varsayılan olarak default kullanır; boş bir ad alanı ("") da default anlamına gelir.

Nesneleri Saklama ve Okuma

# Bytes in, bytes out info = await ironflock.files.put("reports/march.pdf", pdf_bytes, content_type="application/pdf") data = await ironflock.files.get("reports/march.pdf") # Or straight from/to a local file — these stream on the large-object path, # so a multi-gigabyte file never has to fit in memory await ironflock.files.put_file("firmware/v2.bin", "/data/build/v2.bin") await ironflock.files.get_to_file("firmware/v2.bin", "/tmp/v2.bin")
MetotAçıklama
put(key, data, …)Bir nesneyi saklar (Python’da bytes, JavaScript’te Uint8Array, Go’da []byte). Nesnenin url değeri dahil meta verilerini döndürür
get(key, namespace?)Nesnenin içeriğini döndürür. Satır içi limiti aşan bir nesne doğrudan nesne depolamadan gelir; bunun mümkün olmadığı yerlerde ise yönlendirici üzerinden bayt aralıkları halinde gelir (bkz. Büyük Nesneler)
put_file(key, path, …) / get_to_file(key, path, …)Python ve Go (PutFile / GetToFile; Go ayrıca PutReader ile bir io.Reader’dan ve GetTo ile bir io.Writer’a akış olarak aktarır). Yerel bir dosyadan saklar ya da yerel bir dosyaya yazar. Büyük nesne yolunda akış (stream) olarak aktarır
delete(key, namespace?)Bir nesneyi siler
copy(key, to, …)Bir nesneyi, isteğe bağlı olarak başka bir ad alanına kopyalar
move(key, to, …)Önce kopyalar, sonra siler. Atomik değildir — serviste bir taşıma fiili yoktur, bu nedenle başarısız bir silme her iki kopyayı da bırakır

put ve get nesnenin tamamını bellekte tutar. Büyük bir nesne için akış (stream) olarak aktaran dosya varyantlarını kullanın (Go’da ayrıca PutReader ve GetTo). JavaScript’te dosya yolu yardımcıları yoktur, çünkü paket hem Node hem de tarayıcı için tek bir derleme yayımlar — yerel dosyaları fs ile kendiniz okuyup yazın.

Python’da put_file ve get_to_file metotlarının dosya işleri olay döngüsünün dışında çalışır. get_to_file, eksik üst dizinleri oluşturur ve nesnenin ilk baytları elde edilir edilmez dosyayı yerinde yazar: reddedilen bir okuma (böyle bir nesne yok, yetki yok) yola hiç dokunmaz; yarıda başarısız olan bir okuma ise o ana kadar yazılanı bırakır. Bir FIFO, nesne akış halinde geldikçe yazılır ve onu açmak bir okuyucu bekler; bu yüzden kimsenin okumadığı bir FIFO çağrıyı (olay döngüsünü değil) engeller; asyncio.wait_for ondan vazgeçebilir. put_file, bir FIFO’yu saklamadan önce sonuna kadar okur.

Go’da GetToFile da eksik üst dizinleri oluşturur, ancak hedefin yanındaki geçici bir dosyaya indirir ve indirme tamamlanınca onu yeniden adlandırarak yerine koyar: başarısız olan veya iptal edilen bir indirme hiçbir zaman yarım bir dosya bırakmaz ve önceki dosyayı korur. Sembolik bağlantılar izlenir (gösterdikleri dosya yazılır, bağlantılar yerinde kalır); yeni dosya, sürecin izin verdiği ölçüde eski dosyanın sahibini, grubunu ve izin bitlerini alır. Bir FIFO veya bir aygıt, nesne akarken yerinde yazılır. Yanına yeni bir dosya konamayan bir hedef için — örneğin salt okunur veya sözde (pseudo) bir dosya sistemindeki bir hedef — kendiniz açtığınız bir dosyayla GetTo kullanın.

put şunları kabul eder: content_type / contentType (MIME türü; ad alanı hangilerine izin verildiğini kısıtlayabilir) ve namespace. Python’da bunlar anahtar kelime argümanlarıdır; JavaScript’te bir seçenekler nesnesinin içine girer; Go’da seçeneklerdir (filestore.ContentType(…), filestore.Namespace(…)).

Listeleme ve İnceleme

MetotAçıklama
list(…)Dosya servisinin listelemesinin tek bir sayfası, varsayılan olarak klasör tarzında: objects, anahtarları öneki / içermeden sürdüren nesneleri, prefixes ise altındaki klasörleri tutar. "" değerinde bir delimiter düz listeler — önek altındaki her nesneyi, alt klasörlerdekiler dahil. Başka bir limit geçmediğiniz sürece bir sayfa en fazla 200 nesne içerir. objects, prefixes, is_truncated / isTruncated / IsTruncated ve sonraki sayfa için geri geçirilecek bir cursor döndürür
iter(…) / iterate(…)Bir önek altındaki her nesne üzerinde, alt klasörlerdekiler dahil, sayfalamayı otomatik yaparak ilerleyen asenkron yineleyici. Python’da iter, JavaScript’te iterate, Go’da Iter (bir range döngüsü için bir iter.Seq2[*ObjectInfo, error]) olarak adlandırılır
stat(key, namespace?)İçeriğini aktarmadan tek bir nesnenin meta verileri
exists(key, namespace?)Bir nesnenin var olup olmadığı
namespaces()Bu uygulamanın kullanabileceği ad alanları
usage(…)Uygulamanın ne kadar depolama alanı kullandığı — aşağıya bakın
catalog()Ad alanları ile sunucunun bildirdiği limitler ve kotalar. Bir kez getirilir ve önbelleğe alınır: catalog(refresh=True) / catalog(true) / RefreshCatalog(ctx) onu yeniden getirir

Klasörler. / ile biten bir önek bir klasörü adlandırır: iter(prefix="2026/") / iterate({ prefix: "2026/" }) / Iter(ctx, filestore.Prefix("2026/")), 2026/a.txt ve 2026/sub/c.txt öğelerini verir, ancak 2026-notes.txt öğesini vermez. list bir klasörü adıyla açamaz, çünkü dosya servisi / ile biten bir listeleme önekini reddeder (FleetFiles v0.2 INTERNAL yanıtını verir): 2026 önekiyle çağrılan list, nesneler arasında 2026-notes.txt öğesini, önekler arasında ise 2026/ klasörünü döndürür. Servis anahtarları Unicode normalleştirme biçimi C’de saklar; bu yüzden klasör önekini de NFC olarak verin. Önekin başka bir biçimi altındaki bir anahtarla karşılaşan bir yineleme, her anahtarı atlamak yerine başarısız olur.

Nesneler üç SDK’da da aynı alanlarla, her dilin adlandırma stiline uygun olarak tanımlanır: namespace, key, size, etag, content_type / contentType, last_modified / lastModified, checksum_sha256 / checksumSha256 ve url — Go’da filestore.ObjectInfo türünün Namespace, Key, Size, ETag, ContentType, LastModified, ChecksumSHA256 ve URL alanları.

Depolama Kullanımı ve Kota

usage, tek bir çağrıyla doğrudan nesne deposundan yanıt alır; bu nedenle toplamlar SDK tarafından toplanmış değil, kesindir:

u = await ironflock.files.usage() print(u.size_bytes, u.object_count, u.quota_bytes, u.free_bytes) # Break the total down per namespace (costs one listing per namespace) detailed = await ironflock.files.usage(detail=True) print(detailed.per_namespace) # {"default": 1048576, "frames": 73400320}

Go’da alanlar filestore.StorageUsage türünün SizeBytes, ObjectCount, QuotaBytes, FreeBytes ve PerNamespace alanlarıdır.

AlanAnlamı
size_bytes / sizeBytesŞu anda saklanan bayt miktarı
object_count / objectCountSaklanan nesne sayısı
quota_bytes / quotaBytesUygulanan bütçe. 0 sınırsız anlamına gelir
free_bytes / freeBytesKalan bayt miktarı. -1 sınırsız anlamına gelir — burada 0 bildirmek “dolu” gibi okunurdu
per_namespace / perNamespaceAd alanı başına bayt miktarı. Yalnızca ayrıntılı dökümü istediğinizde bulunur

Ad alanı başına döküm varsayılan olarak kapalıdır, çünkü depo bunu doğrudan yanıtlayamaz: hesabı depolama alanı başına tutar ve bir ad alanı yalnızca bir önektir, dolayısıyla SDK’nın boyutları toplamak için her ad alanını listelemesi gerekir. Bunu istediğinizde isteyin, sıcak bir kod yolunda değil.

Birbirinden ayrı tutulması gereken iki farklı kota vardır. catalog() her ikisini de bildirir:

AlanAnlamı
quota_bytes / quotaBytesGerçekte uygulanan değer; nesne deposundan okunur — proje kullanıcısının ayarı
suggested_quota_bytes / suggestedQuotaBytesUygulamanın veri şablonunun istediği değer. Hiçbir şey istemediyse 0

Go’da Catalog(ctx), QuotaBytes ve SuggestedQuotaBytes alanlarına sahip bir *filestore.Catalog döndürür.

Bir kullanıcı uygulamanın bütçesini yükselttiğinde ya da düşürdüğünde bu iki değer birbirinden ayrılır; uygulanan değerin şablondan değil depodan okunmasının nedeni de budur — uygulamanın yeniden dağıtılması, kullanıcının seçimini sessizce sıfırlamamalıdır. Bir arayüz her ikisini de gösterebilir (“uygulama X öneriyor, siz Y ayarladınız”). Uygulama her zaman ilkini kullanır. Kullanıcı bütçeyi istediği zaman değiştirebilir ve catalog() onu son getirildiği andaki haliyle bildirir: güncel değeri usage() ile okuyun.

Nesneleri Paylaşma

İki tür bağlantı vardır ve aradaki fark önemlidir:

MetotÖmürKimler okuyabilir
url(key, …)KalıcıYalnızca bu veri arka ucu üzerinde READ yetkisine sahip, kimliği doğrulanmış bir istek sahibi — her istekte denetlenir (bir karar en fazla 5 dakika önbellekte tutulur). Bir tablo sütununda saklanması güvenlidir
share_url / shareUrl / ShareURLSüreli (varsayılan 15 dakika, sunucu tarafından sınırlanır)Bağlantıyı elinde tutan herkes. Kullanıldığında yetkilendirmeyi yeniden denetleyen hiçbir şey yoktur

share_url / shareUrl bir taşıyıcı (bearer) yetkidir: geçici erişime ihtiyacı olan bir kişiye verin ve veritabanında saklamayın. Bir panonun görüntülediği her şey için url kullanın.

url, dağıtımın bir HTTP kenarı bulunmadığı durumlarda (örneğin düz HTTP çalışan bir appliance) None / undefined / "" (Go) döndürür — bu, get’e geri dönmeniz gerektiğinin işaretidir. share: none olarak tanımlanmış bir ad alanında kalıcı URL de çalışmaz, ancak katalog bir ad alanının nasıl paylaşıldığını bildirmediği için url bunu ayırt edemez: URL’yi yine de döndürür ve dosya kenarı (file edge) ona 404 ile yanıt verir. Bu tür nesneleri get ile okuyun; share_url / shareUrl / ShareURL bağlantıları share ayarına bağlı değildir. Nesnenin etag değerini version argümanı olarak (Go’da filestore.Version(etag)) geçmek, tarayıcıların yanıtı değişmez (immutable) biçimde önbelleğe almasını sağlar.

Python ve Go’da cloud_url(key, …) / CloudURL(ctx, key, …), kalıcı URL’yi bir appliance’ın bulut dosya tüneli üzerinden döndürür (https://i<instanceKey>-files.<cloud-edge>): appliance çevrimiçi olduğu sürece internetten erişilebilir ve url ile aynı yetkilendirmeye tabidir. Bulutta barındırılan dağıtımlarda (url değerinin zaten internetten erişilebildiği yerlerde), HTTP kenarının bulunmadığı yerlerde ve veri arka ucunun bulut paylaşımı kapalıyken None (Go’da "") döndürür. Kullanıcı bunu istediği zaman açıp kapatabilir; bu nedenle cloud_url / CloudURL, önbellekteki katalog 30 saniyeden eskiyse kataloğu yeniden okur.

upload_url / uploadUrl / UploadURL, doğrudan yükleme kabul eden süreli bir URL (varsayılan olarak 1 saat geçerli) üretir ve url, method, headers ile expires_in / expiresIn döndürür (Go’da URL, Method, Headers ve ExpiresIn alanlarına sahip bir *filestore.UploadTarget). Nesnenin URL üretilirken belirlenen içerik türüyle saklanması için başlıkları verildiği gibi gönderin. Ad alanının içerik türleri ve boyut sınırı, bildirilen bir size ve kota, URL kullanıldığında değil üretildiğinde denetlenir: URL yalnızca ana makine (host) için imzalanır; bu nedenle onu elinde tutan herkes, süresi dolana kadar anahtarına herhangi bir içerik yazabilir. share_url / shareUrl gibi bu da bir taşıyıcı (bearer) yetkidir — yazan türden.

Büyük Nesneler

SDK aktarım yolunu boyuta göre otomatik olarak seçer — yapılandırılacak bir şey yoktur:

Nesne boyutuNasıl aktarılır
Satır içi limite kadar (şu anda 6 MiB)Mesaj yönlendiricisi üzerinden tek bir çağrı
Daha büyükYönlendiriciyi atlayarak, HTTPS üzerinden doğrudan nesne depolamaya
Daha büyük, doğrudan yolun bulunmadığı yerlerde okumaMesaj yönlendiricisi üzerinden bayt aralıkları halinde

Kesin limit, sunucu tarafından çalışma zamanında catalog() içinde inline_max_bytes / inlineMaxBytes / InlineMaxBytes olarak bildirilir; böylece yeni bir SDK sürümü çıkmadan yükseltilebilir.

Doğrudan yol, URL’leri önceden imzalayabilen (presign) bir dağıtım ve yalnızca yönlendiriciye değil nesne depolama sunucusuna da erişebilen bir cihaz gerektirir. Bunlardan biri eksik olduğunda — katalog dağıtımın önceden imzalayamadığını söylediğinde (varsayılan olarak bir yerinde (on-premises) appliance), okuma URL’sinin üretilmesi NOT_SUPPORTED yanıtını verdiğinde veya herhangi bir bayt gelmeden önce nesne depolamaya erişilemediğinde — get (ve Python’da get_to_file, Go’da GetTo ile GetToFile) bunun yerine nesneyi yönlendirici üzerinden bayt aralıkları halinde okur (FleetFiles v0.1.33 ve sonrası); her aralık en fazla satır içi limit kadardır. Her aralık ayrı bir okumadır: böyle bir okuma sırasında değiştirilen bir nesne okumayı INTERNAL ile başarısız kılar (“object changed while it was read”). Yazmaların böyle bir geri dönüş yolu yoktur.

Yazmalar için geriye iki tavan kalır ve her ikisi de hangisine takıldığınızı belirten bir nedenle TOO_LARGE bildirir:

  • 5 GiB — nesne deposunun tek seferlik yükleme limiti. Çok parçalı (multipart) yükleme henüz uygulanmadı.
  • Doğrudan uç noktanın bulunmadığı yerlerde satır içi limit — önceden imzalayamayan bir dağıtım (varsayılan olarak bir appliance) daha büyük bir nesneyi hiç saklayamaz. Hiçbir yeniden deneme ya da daha küçük parça işe yaramaz ve mesaj bunu açıkça söyler.

Doğrudan yolun sahada sık görülen iki arızası, yetkilendirme sorunu gibi görünmek yerine kendi kodlarını alır: PRESIGN_UNREACHABLE (yalnızca yönlendiriciye izin veren bir proxy — bir okuma aralıklara geri döner, bir yazma başarısız olur) ve CLOCK_SKEW (nesne deposu, 15 dakikadan fazla sapmış istekleri reddeder — cihazdaki NTP’yi kontrol edin).

Dosya Depolama Hataları

Dosya servisinin veya doğrudan bir aktarımın başarısızlığı, kararlı bir code ve insan tarafından okunabilir bir reason taşıyan bir FileStoreError yükseltir (Python) / fırlatır (JavaScript) / döndürür (Go). reason üzerinde değil, her zaman code üzerinde dallanın. Yerel dosya hataları, iptal edilen bir çağrı ve aşağıda eşlenenler dışındaki yönlendirici düzeyindeki WAMP hataları olduğu gibi yükseltilir.

from ironflock.filestore import FileStoreError try: await ironflock.files.put("huge.bin", payload) except FileStoreError as e: if e.code == "QUOTA_EXCEEDED": print("Filestore is full:", e.reason) else: raise
KodAnlamı
NOT_AUTHORIZEDÇağıran taraf bu işlemi gerçekleştiremez
NO_SUCH_NAMESPACEAd alanı veri şablonunda tanımlı değil
NO_SUCH_OBJECTAnahtar mevcut değil
TOO_LARGETek çağrılık aktarım limitini aşıyor
OBJECT_TOO_LARGEAd alanının kendi maxObjectBytes değerini aşıyor
QUOTA_EXCEEDEDDosya deposu dolu
CONTENT_TYPE_NOT_ALLOWEDAd alanı contentTypes değerini kısıtlıyor
INVALID_KEYHatalı biçimlendirilmiş bir anahtar veya önek (aşağıya bakın; FleetFiles v0.2 bunu hâlâ INTERNAL olarak bildirir)
INVALID_RANGENesnenin dışında kalan bir bayt aralığı; SDK’lar asla böyle bir aralık istemez
NOT_SUPPORTEDArka uç bunu yapamıyor
NOT_AVAILABLEBu dağıtımda dosya servisi yok — ya da henüz yok: bir platform yeniden başlatmasından sonra veya dosya servisi prosedürlerini kaydederken. Çağrı hiçbir yerde çalışmadı ve tekrarlanabilir
PRESIGN_UNREACHABLENesne depolamaya doğrudan erişilemiyor (bir proxy mi?)
CLOCK_SKEWCihaz saati fazlaca sapmış
INTERNALBunların dışındaki her şey — aralıklı bir okuma sırasında değişen bir nesne de

Daha yeni bir sunucu, bu SDK sürümünün bilmediği kodlar sunabilir. Bunlar tek bir kategoriye indirgenmeden code olarak geçirilir; bu nedenle tanınmayan bir değeri genel bir hata olarak ele alın.

Dosya çağrıları bağlantıyı en fazla 10 saniye bekler (start() / Start öncesinde yapılan bir çağrı, aynı süre içinde onu da bekler) ve yeniden denenmez: tablo işlemlerinden farklı olarak bir platform yeniden başlatmasını atlatamazlar; bu yüzden böyle bir yeniden başlatma sırasında bir çağrı, dosya servisi yeniden kaydolana kadar NOT_AVAILABLE ile başarısız olabilir. Böyle bir çağrı hiçbir yerde çalışmamıştır, bu nedenle uygulamanız onu tekrarlayabilir.

Anahtarlar. Anahtarlar konusunda yetkili olan dosya servisidir; SDK’lar anahtarları ve önekleri verildiği gibi gönderir. Hatalı biçimlendirilmiş bir anahtar veya önek — boş; başında veya sonunda / bulunan (iter / iterate için bir klasör öneki hariç); boş, . veya .. segmenti ya da . ile biten veya boşlukla başlayan ya da biten bir segmenti olan; \ : * ? " < > | ^ ~ karakterlerinden birini, bir kontrol karakterini veya bir Unicode biçim karakterini içeren; 900 baytı, 20 segmenti veya segment başına 255 baytı aşan; ya da ayrılmış _sys/ öneki altındaki — anahtar hatalarını sınıflandıran bir dosya servisi tarafından INVALID_KEY ile, FleetFiles v0.2 tarafından ise INTERNAL ile reddedilir. Zaman damgalarına dikkat edin: 2026-10-09T12:00:00Z, : nedeniyle geçerli bir anahtar segmenti değildir.

Python’da FileStoreError, ironflock.filestore içinden içe aktarılır; JavaScript’te ise paket kökünden dışa aktarılır (import { FileStoreError } from "ironflock"); Go’da *filestore.Error’dır (ayrıca ironflock.FileStoreError) ve kodlar filestore.CodeQuotaExceeded gibi sabitlerdir.

Cihazlar Arası İletişim

registerDeviceFunction / register_device_function

Aynı uygulamayı (aynı aşamada) çalıştıran diğer cihazların ve pano widget eylemlerinin çağırabileceği bir prosedür kaydeder. SDK tam URI’yi, <SWARM_KEY>.<DEVICE_KEY>.<APP_KEY>.<STAGE>.<topic>, sizin için oluşturur; burada STAGE, ENV değeri PROD olduğunda (büyük/küçük harf fark etmeksizin) PROD, aksi halde DEV olur. SDK, herhangi bir şey göndermeden önce boş bir konuyu ve eksik ya da 0 olan bir cihaz, proje veya uygulama anahtarını reddeder; callDeviceFunction / call_device_function de öyle. Yönlendirici bir uygulamadan başka hiçbir kaydı kabul etmez ve yalnızca tekli (single) kayıtları kabul eder (bkz. Bir Uygulamanın Kullanabileceği URI’ler). Bağlantı yokken metot, bir bağlantı için yeniden bağlanma penceresi boyunca (varsayılan olarak 60 saniye, bkz. Bağlantı Güvenilirliği) bekler. Kayıt her yeniden bağlanmadan sonra geri yüklenir. Metot, kaydın tanıtıcısı olan bir Registration döndürür: onun unregister() metodu kaydı kaldırır (bkz. unsubscribe / unregister).

def add(a, b): return a + b await ironflock.register_device_function("com.myapp.add", add)

register(), register_device_function() için bir takma addır.

Eski adlar olan register_function / registerFunction / RegisterFunction ve call_function / callFunction / CallFunction hâlâ çalışır, ancak kullanımdan kaldırılmıştır.

ENV değerini geçersiz kılan uygulamalar: 1.8.6’ya (Python) ve 1.8.4’e (JavaScript) kadarki SDK sürümleri, ham ENV değerini aşama segmentine koyuyordu. Bu yalnızca bir uygulama ENV değerini kendisi prod gibi farklı bir yazımla ayarladığında fark yaratır: bu durumda o sürümlerdeki cihazlar ile daha yeni sürümlerdeki cihazlar birbirlerinin fonksiyonlarını çağıramaz.

callDeviceFunction / call_device_function

Aynı uygulamanın başka bir cihazı tarafından kaydedilmiş bir prosedürü çağırır. SDK, hedef cihazın anahtarını kullanarak tam WAMP konusunu otomatik olarak oluşturur: <SWARM_KEY>.<device_key>.<APP_KEY>.<STAGE>.<topic>; bu, registerDeviceFunction / register_device_function metodunun hedef cihazda kaydettiği URI’nin aynısıdır.

result = await ironflock.call_device_function( 42, # target device key "com.myapp.add", # procedure name args=[3, 5] # arguments ) print(result) # 8

call

Tam bir WAMP URI kullanarak uzak prosedür çağırır. Bir uygulama some.full.wamp.topic gibi bir adı kaydedemez; bu yüzden böyle bir ad yalnızca platform servislerinin uygulamanın veri realm’inde kaydettiği prosedürlere, örneğin veri arka ucunun ve dosya depolamanın prosedürlerine ulaşır. Uygulamanızın başka bir cihazının kaydettiği bir fonksiyonu çağırmak için callDeviceFunction / call_device_function kullanın.

result = await ironflock.call("some.full.wamp.topic", args=[42])

Bir Uygulamanın Kullanabileceği URI’ler

Uygulama container’ınız kendi veri realm’ine, realm-<SWARM_KEY>-<APP_KEY>-<dev|prod>, app yönlendirici rolüyle katılır. Yönlendirici oradaki her yayımlama, abonelik, çağrı ve kaydı bu rolün izin listesine göre denetler. SDK’nın kendi metotları bu listenin içinde kalır; kurallar, publish, subscribe veya call metotlarına kendi URI’lerinizi verdiğinizde ya da connection nesnesini (Go’da Connection()) doğrudan kullandığınızda önem kazanır. Reddedilen bir eylem wamp.error.not_authorized ile başarısız olur. Python’da metot bir RuntimeError yükseltir ve wamp_error_uri(err) URI’yi döndürür; JavaScript’te hata, error alanı URI olan bir WampError nesnesidir; Go’da ironflock.WampURI(err) bunu döndürür.

Kendi realm’inizdeki URIİzin verilenKullanan
Kendi adlarınız, ör. com.myapp.statusyayımlama, abonelik (önek abonelikleri de), çağrı — asla kayıtpublish, subscribe, call
<SWARM_KEY>.<APP_KEY>.<table>, bulk.<SWARM_KEY>.<APP_KEY>.<table>yayımlama — asla abonelik– (tablo yazma konuları; SDK’nın tablo yazmaları bunun yerine ekleme yapar)
transformed.<table>, transformed.bulk.<table>yalnızca aboneliksubscribeToTable / subscribe_to_table
databackend.errors.…, files.events…yalnızca abonelikVeri arka ucunun hata ve dosya olayları
<SWARM_KEY>.<DEVICE_KEY>.<APP_KEY>.<STAGE>.<name>kayıt (single), çağrı, yayımlama — asla abonelikregisterDeviceFunction / register_device_function, callDeviceFunction / call_device_function
append.…, appendBulk.…, history.transformed.…, secret.reveal.…, secret.verify.…, files.read.…, files.write.…çağrı (SDK bunları çağırır)Tablo, geçmiş, gizli değer ve dosya metotları
sys.appaccess.list, sys.appaccess.resolveçağrılistConsumableApps / list_consumable_apps, connectToApp / connect_to_app, connectToAllApps / connect_to_all_apps
wamp.session.getçağrıJavaScript SDK’sının heartbeat’i

Kimliği denetlenen adlar. Bir rakamla başlayan adlar — tablo yazma konuları ve cihaz fonksiyonu URI’leri — ayrıca platformun kimlik denetiminden geçer; bu denetim onları realm’inizin SWARM_KEY değerine bağlar. Bir kayıt yalnızca kendi cihazınıza ait, realm’inizin SWARM_KEY, APP_KEY ve aşama (stage) değerlerini taşıyan bir fonksiyon URI’si için kabul edilir; önek veya joker karakterli bir kayıt ise yalnızca bu dört segmenti sabitlediğinde kabul edilir. Yayımlama ve çağrı yalnızca realm’inizin SWARM_KEY değerini gerektirir: başka bir APP_KEY içeren bir tablo konusuna yayımlanan satır kabul edilir, ancak hiçbir veri arka ucuna ulaşmaz ve kaybolur. Bu URI’leri SDK’nın oluşturmasına bırakın.

Ayrılmış adlar. Yönlendirici, yukarıdaki iki uygulamalar arası prosedür dışında sys. adlarını ve wamp.session.get dışında wamp. adlarını reddeder. Tablodaki diğer adlar platforma aittir: kendi adlarınızı bir rakamla, bulk., transformed., databackend.errors., files., append., appendBulk., history. veya secret. ile başlatmayın. Diğer her ilk segment, uygulamanızın kendi konu alanıdır.

Ham tablo konularına kimse abone olmaz. Bu konular satırı tam olarak gönderildiği gibi, gizli sütunların düz metni dahil taşır; veri arka ucu gizli sütunları ancak satırı saklarken şifreler. subscribeToTable / subscribe_to_table bunun yerine saklanan satırları transformed.<table> konusundan, tiplendirilmiş ve gizli sütunları maskelenmiş olarak okur.

Diğer uygulamaların verileri salt okunurdur. Bir sağlayıcının realm’inde uygulamanız (app_reader yönlendirici rolü), heartbeat için kullanılan wamp.session.get dışında yalnızca transformed.… ve files.events… konularına abone olabilir ve history.transformed.… ile files.read.… prosedürlerini çağırabilir — yayımlama, kayıt, yazma ve gizli değer prosedürleri yoktur.

Cihaz Meta Verisi

setDeviceLocation / set_device_location

Platformdan cihazın GPS konumunu güncellemesini ister; IronFlock haritaları bu konumu gerçek zamanlı olarak gösterir.

Şu anda kullanılamıyor: uygulamanın veri realm’inde bu çağrıyı yanıtlayan bir platform servisi henüz yok, bu yüzden çağrı wamp.error.no_such_procedure ile başarısız olur. O zamana kadar konumları kendi tablonuzda tutun.

await ironflock.set_device_location(long=8.6821, lat=50.1109)
ParametreAralık
long-180 ile 180
lat-90 ile 90

Konum geçmişi saklanmaz. Konumu zaman içinde takip etmek için ayrı bir tablo oluşturun ve publish_to_table / publishToTable kullanın.

getRemoteAccessUrlForPort

Uygulamanın port-template.yml dosyasında tanımlanan bir portun, tüneli etkinleştiğinde erişilebilir olduğu URL’yi döndürür.

url = ironflock.getRemoteAccessUrlForPort(8080) # "https://<device_key>-<app_name>-8080.app.ironflock.com" vnc = ironflock.getRemoteAccessUrlForPort(5900, protocol="tcp") # "tcp://app.ironflock.com:<the tunnel's remote port>"
ParametreTürAçıklama
portint / numberport-template.yml dosyasında tanımlandığı şekliyle port
protocolstr / string, isteğe bağlıPortun protokolü: "http" (varsayılan), "https", "tcp" veya "udp", büyük/küçük harf fark etmeksizin; çevresindeki boşluklar yok sayılır ve boş bir protokol "http" anlamına gelir
remote_port_environment / remotePortEnvironmentstr / string, isteğe bağlıYalnızca tcp/udp: REMOTE_PORT_FOR_<port> yerine uzak portu tutan değişken — şablondaki portun kendi remote_port_environment değeri; 0.19.8 öncesi cihaz ajanları buna ihtiyaç duyar

http ve https portları, cihaz ajanının enjekte ettiği tünel alan adında (TUNNEL_DOMAIN) <device_key>-<app name, lower case>-<port> tünel etiketi altında (https portları platformun secure- önekiyle) her zaman bir https:// URL’si olarak sunulur. Yerinde (on-premises) bir appliance’a ait bir cihazda (ajan INSTANCE_KEY enjekte eder) bunun yerine bulut üzerinden yönlendirilen https://i<INSTANCE_KEY>-<label>.<CLOUD_TUNNEL_DOMAIN> yolu döndürülür.

Bir tcp veya udp URL’si, tünelin atadığı ve cihaz ajanının REMOTE_PORT_FOR_<port> olarak duyurduğu (ajan 0.19.8 ve sonrası) genel portu taşır: <protocol>://<TUNNEL_DOMAIN>:<remote port>. Bir appliance’ın cihazında, ajan duyurduğu sürece internete açık port olan REMOTE_PORT_FOR_<port>_CLOUD tercih edilir; bu port görünmeden önce ve ajan onu kaldırdıktan sonra yeniden (bulut yönlendirmesi kapatıldığında) appliance’ın yerel URL’si döndürülür. 0 değerindeki bir port henüz atanmamıştır.

Port değerleri /data/env dizininden canlı olarak okunur; bu nedenle sonucu önbelleğe almak yerine metodu yeniden çağırın. URL’nin karşılayamadığı bazı durumlar:

  • Cihaz ajanı yalnızca üretim (PROD) kurulumlarının portları için tünel açar. Bir geliştirme (DEV) container’ında http(s) URL’si, bu cihazdaki aynı uygulamanın PROD kurulumunun URL’sidir; tcp/udp ise hiçbir URL vermez. Bir DEV uygulamasına bunun yerine cihazın LAN adresi üzerinden ulaşın (DEVICE_LAN_IP, DEVICE_PORT_FOR_<port>).
  • Alan adı olmadan (düz mod) kurulmuş bir appliance’ın uç cihazında ajan TUNNEL_DOMAIN değerini localhost olarak ayarlar; bu yüzden orada oluşturulan URL’ler localhost’u gösterir: böyle bir appliance, uygulama portlarını kendi ana makine portlarında sunar ve bunu bir tünel URL’si ifade edemez.
  • Ayarlanmamış veya boş tünel alan adları varsayılan olarak app.ironflock.com olur. Platform bugün CLOUD_TUNNEL_DOMAIN değerini ayarlamaz: uygulama bu değişkeni ortam ayarlarında kendisi ayarlamadıkça bir appliance’ın URL’leri app.ironflock.com kullanır.
  • Root dışında bir kullanıcıyla çalışan bir container’da değerler, container’ın başladığı andaki değerlerdir (bkz. Ortam Değişkenleri).

URL oluşturulamadığında metot None / null (Go’da "" ve false) döndürür: cihaz anahtarı veya uygulama adı eksikse, bir tcp/udp portu için henüz uzak port duyurulmamışsa (veya değeri 0 ise), protokol bilinmiyorsa ya da etiket geçerli bir DNS etiketi değilse (63 karakterden uzun veya noktalı bir uygulama adı). Tarayıcıda ortam yoktur: http(s) URL’si deviceKey ve appName seçeneklerinden app.ironflock.com üzerinde oluşturulur.

Bağlantı Özellikleri & Yaşam Döngüsü

ÖzellikTürAçıklama
is_connectedboolPlatform bağlantısının aktif olup olmadığı
connectionCrossbarConnectionAltta yatan bağlantı örneği (gelişmiş kullanım)
filesFileStoreUygulamanın yönetilen dosya depolaması (bkz. Yönetilen Dosya Depolama)
MetotAçıklama
run()Bağlantıyı başlatır, mainFunc’ı çalıştırır (engelleme), ardından bağlantıyı durdurur
await start()Bağlantıyı asenkron olarak başlatır. Bundan önce yapılan işlemler, kendi bekleme süreleri içinde onu bekler (bkz. Bağlantı Güvenilirliği)
await stop()Bağlantıyı ve tüketilen uygulama bağlantılarını durdurur ve ana görevi (mainFunc) iptal eder. Bağlantılar realm’lerinden ayrılır ve sonrasında yeniden bağlanmaz; start() yeniden bağlanır. Hâlâ bir bağlantıyı veya start() çağrısını bekleyen her işlem hemen başarısız olur; hâlâ bekleyen bir start() veya connect_to_app da öyle. stop() sonrasında yapılan bir işlem bir sonraki start() çağrısını bekler (bkz. Bağlantı Güvenilirliği)
await run_async()Bağlantıyı başlatır ve asenkron olarak çalıştırmaya devam eder

run() ve run_async(), mainFunc döndüğü veya bir istisna yükselttiği anda bağlantıyı durdurur; yükseltilen istisna, durdurmanın ardından yeniden yükseltilir. Bu nedenle yalnızca abone olan veya cihaz fonksiyonları kaydeden bir mainFunc, örneğin await asyncio.Event().wait() ile çalışmaya devam etmelidir. mainFunc bir async fonksiyon (async def) olmalıdır. mainFunc verilmezse run() ve run_async() bağlantıyı süreç sona erene kadar açık tutar.

Bağlantı Güvenilirliği

SDK kendiliğinden yeniden bağlanır. Bağlantı koptuğunda router geri gelene kadar yeniden dener, ardından her aboneliği ve kayıtlı her cihaz fonksiyonunu geri yükler — yeniden bağlandıktan sonra tekrar abone olmanız gerekmez ve elinizdeki tanıtıcılar geçerli kalır: her birinin active değeri, şu anda router’da etkin olup olmadığını söyler (bkz. unsubscribe / unregister). Tablo abonelikleri, bağlantı kopukken saklanan satırları da teslim eder (bkz. subscribeToTable); kendi konularınızdaki mesajlar ise saklanmaz, bu yüzden bu arada yayımlananlar kaybolur. Biri geri yüklenemezse diğerleri yine de geri yüklenir; başarısız olan ise oturum sürdüğü müddetçe yeniden denenir — 1 saniye sonra, 30 saniyeye kadar ikiye katlanarak ve her bekleme %15’e kadar değiştirilerek — ve her yeniden bağlanmadan sonra tekrar denenir: router onu daha önce kabul etmişti, dolayısıyla reddi geçicidir; örneğin platformun bir cihaz fonksiyonu için yaptığı kimlik denetiminin bir anlığına güvenli tarafta kalarak reddetmesi (fail closed) gibi. İlk başarısızlık bir uyarı olarak kaydedilir; geri yükleme başarılı olduğunda da kaydedilir.

Tablo işlemleri — tablo yazmaları, geçmiş, seri ve gizli değer okumaları ile tüketilen bir uygulamanın geçmiş ve seri okumaları — router veya platform güncellemesi gibi bir platform yeniden başlatmasını da atlatır. Bağlantının geri gelmesi için reconnect_window (Python, saniye cinsinden) / reconnectWindowMs (JavaScript) / WithReconnectWindow (Go, bir time.Duration) kadar, varsayılan olarak 60 saniye beklerler; start() / Start öncesinde yapılan bir işlem de aynı pencere içinde onu bekler. Ayrıca veri arka ucu prosedürlerini henüz sunmadığı sürece yeniden denerler: router wamp.error.no_such_procedure yanıtını verir ya da veri arka ucu, kaydının önüne geçen bir çağrıyı “client has no handler for registration” ile reddeder. Böyle bir çağrı hiçbir zaman bir işleyiciye ulaşmamıştır; bu yüzden bir yeniden deneme bir satırı asla iki kez yazmaz; diğer her hata geldiği gibi yükseltilir. Bir tablo aboneliğinin kaçırılan satırları getiren okuması da bu okumalardan biridir.

Tablo yazmalarına publishToTable / publish_to_table, publishRowsToTable / publish_rows_to_table ve reportError / report_error de dahildir: appendToTable ve appendRowsToTable ile aynı ekleme prosedürlerini çağırırlar; bu yüzden veri arka ucu yeniden başlarken yazılan bir satır kaybolmaz.

publish, subscribe, subscribeToTable / subscribe_to_table (tüketilen bir uygulamanınki de) ve registerDeviceFunction / register_device_function de yeniden bağlanma penceresi içinde bir bağlantı bekler; böylece kısa bir kesinti onları başarısız kılmaz. Yeniden denenmezler; bir abonelik veya kayıt sonraki her yeniden bağlanmadan sonra geri yüklenir.

Diğer her işlem — call, callDeviceFunction / call_device_function, setDeviceLocation / set_device_location, dosya çağrıları ve uygulamalar arası sorgulamalar ile bağlantı açma işlemleri — bir bağlantı için en fazla 10 saniye bekler ve yeniden denenmez. start() / Start öncesinde yapılan bir işlem, bu 10 saniye içinde onu bekler. Beklemesi içinde bağlantı bulamayan bir işlem, bekleme süresini saniye cinsinden belirten bir hatayla başarısız olur: Python’da IronFlock metotları nedeni bir TimeoutError olan bir RuntimeError yükseltir; JavaScript’te bu düz bir Error’dır; Go’da ise wamp.ErrNotConnected’ı saran bir hata. unsubscribe ve unregister hiç beklemez: bağlantı kopukken de hemen etkili olurlar (bkz. unsubscribe / unregister).

0 pencereyi kapatır: bu işlemler bu durumda diğer her işlem gibi davranır. Bir bağlantı için 10 saniye bekler ve yeniden denenmezler; bu yüzden bir platform yeniden başlatmasının hemen ardından kaçırılan satırların teslimi de yeniden denenmez. Negatif bir pencere ve Python ile JavaScript’te ayrıca NaN veya sonsuz bir değer, IronFlock nesnesi oluşturulurken reddedilir (bkz. Yapıcı Seçenekleri).

Oturumu kapandığında (router onu kapattığında, bağlantı koptuğunda ya da stop() çağrıldığında) zaten gönderilmiş olan bir istek, yanıt beklemek yerine hemen başarısız olur ve yeniden denenmez: işleyicisine ulaşmış olabilir. Python’da hatanın nedeni (cause), kapanış nedenini (ör. wamp.close.system_shutdown) taşıyan autobahn ApplicationError hatası ya da bağlantı koptuysa TransportLost’tur. JavaScript’te hata, error alanı kapanış nedeni olan bir WampError nesnesidir: router’ın bildirdiği neden, stop() sonrasında wamp.close.goodbye_and_out ya da bağlantı koptuğunda wamp.close.transport_lost. Go’da böyle bir istek, wamp.ErrNotConnected’ı (Stop’tan sonra wamp.ErrStopped’u) saran bir hatayla başarısız olur.

Özel bir durum, erişilebilir olan ancak uygulama için henüz bir realm’i bulunmayan router’dır. Eşzamanlı kurulum yarışında uygulama konteyneri, veri arka ucu realm’ini hazırlamadan önce başlar; bu yüzden ilk katılma denemeleri wamp.error.no_such_realm ile reddedilir. SDK birkaç saniyede bir yeniden dener ve realm oluştuğu anda uygulama ayağa kalkar. Bir dakika sonra hâlâ eksik olan bir realm büyük olasılıkla hiç oluşmayacaktır — uygulama silinmiştir ya da bu stage için bir veri arka ucu yoktur —, bu nedenle SDK o andan itibaren router’a sonsuza kadar her saniye istek göndermek yerine iki dakikada bir denemeye yavaşlar. Realm ortaya çıktığında ya da router’ın kendisi gidip geri geldiğinde hızlı tempo geri döner.

stop() / Stop her beklemeyi hemen sona erdirir. Hâlâ bir bağlantıyı — ya da start() / Start öncesinde yapılmışsa onu — bekleyen bir işlem, SDK’nın durdurulma hatasıyla başarısız olur; iki yeniden deneme arasında bekleyen bir tablo çağrısı da öyle: Python’da IronFlock bağlantısının durdurulduğunu belirten bir ConnectionError (IronFlock metotları bunu RuntimeError hatalarının nedeni olarak yükseltir), JavaScript’te bir ConnectionStoppedError, Go’da ise wamp.ErrStopped’u saran bir hata. Örneğin henüz var olmayan bir realm’e ilk katılmasını hâlâ bekleyen bir start(), Connection to realm <realm> stopped before it opened ile başarısız olur; Go’da Start, wamp.ErrStopped’u saran bir hata döndürür. Bir sağlayıcının bağlantısını hâlâ açmakta olan bir connect_to_app / connectToApp, Connection to app '<app>' (<stage>) aborted by stop() ile başarısız olur; bağlantı yine de katılırsa kapatılır ve çağrı Connection to app '<app>' (<stage>) closed by stop() ile başarısız olur. Go’da ConnectToApp, ironflock: connection to app '<app>' (<stage>) aborted by Stop ile (ya da closed by Stop ile) başarısız olur. stop() ile yarışan bir ret, kendi CrossAppAccessError hatasını korur. Python ve JavaScript’te stop() döndüğünde bağlanmaya çalışan hiçbir şey kalmaz ve ayrılma isteğine yanıt vermeyen bir router’ın bağlantısı 5 saniye sonra kesilir; Go’nun Stop metodu ayrılmayı ctx içinde bekler ve ardından soketi kapatır, Run ise ona 10 saniye tanır.

Python ve JavaScript’te örnek, stop() sonrasında yeniden başlatılabilir: start() yeniden bağlanır ve stop() sonrasında yapılan bir işlem, ilk start() öncesinde yapılan bir işlem gibi bir sonraki start() çağrısını bekler. Go’nun Stop metodu kalıcıdır: ondan sonra yapılan bir işlem hemen wamp.ErrStopped ile başarısız olur.

Daha zor durum, sessizce ölen bir bağlantıdır: boştayken bir NAT ya da proxy iki tarafa da haber vermeden bağlantıyı keser veya bir yük dengeleyicinin arkasındaki router yeniden başlar. Kaybı bildiren hiçbir şey gelmez. Yalnızca veri yayımlayan bir uygulama bunu bir sonraki başarısız yazma işleminde fark eder; ancak yalnızca abone olan bir uygulama hiç yazmaz, dolayısıyla yardım almadan konteyner yeniden başlayana kadar ölü kalır.

Üç SDK da bunu tespit eder. Tespit varsayılan olarak etkindir ve yapılandırma gerektirmez.

Python SDK’sı WebSocket keepalive kullanır: bağlantı boştayken her 30 saniyede bir router’a ping gönderir ve 10 saniye içinde pong bekler. Yanıt gelmezse bağlantı düşürülüp yeniden kurulur. Gelen trafik yaşam kanıtı sayılır, bu yüzden yoğun bir bağlantı hiç yoklanmaz — ping yalnızca bağlantı gerçekten sessizleştiğinde gider.

connectToApp / connect_to_app ile açılan uygulamalar arası bağlantılar genellikle yalnızca abone olur; bu da tam olarak burada korunan durumdur. Otomatik olarak kapsanırlar ve router onları reddettikten sonra da, ret kalıcı hale gelene kadar yeniden bağlanırlar (bkz. connectToApp).

Hata Yönetimi

Başarısız olan bir SDK metodu — geçersiz argümanlarda, kopan bir bağlantıda veya platformdan gelen bir reddetmede — işlemi, konuyu ve nedeni belirten bir mesajla bir istisna yükseltir (Python), reddeder (JavaScript) ya da bir hata döndürür (Go); bu nedenle hayatta kalmasını istediğiniz çağrıları bir try bloğuna sarın — Go’da döndürülen hatayı denetleyin. Bazı başarısızlıklar kodunuza ulaşmaz. Kendi konularınızdan birine yayımlanan bir mesaj, bu arada kapalı olan hiçbir aboneye ulaşmaz. Yeniden bağlanmanın ardından kaçırılan satırları getiren okuma başarısız olursa bu yalnızca günlüğe kaydedilir (bkz. subscribeToTable).

try: rows = await ironflock.getHistory("sensordata", {"limit": 100}) except ValueError as e: # Invalid parameters — e.g. limit out of range, or a malformed filter print(f"Bad query: {e}") except RuntimeError as e: # Not connected, table not in the data-template, or the platform rejected the call print(f"Query failed: {e}")

JavaScript’te router’ın veya çağrılan tarafın bir reddi genellikle bir WampError’dır — ek olarak WAMP hata URI’sini error içinde, hata yükünü ise args / kwargs içinde taşıyan normal bir Error alt sınıfı. Üç tür çağrı farklı şekilde başarısız olur: prosedürü kayıtlı olmayan bir geçmiş, seri, açığa çıkarma veya doğrulama çağrısı bunu belirten ve olası nedenleri sıralayan düz bir Error ile ve ancak yeniden bağlanma penceresinin tamamı dolduktan sonra başarısız olur, çünkü wamp.error.no_such_procedure yeniden denenir; bir dosya çağrısı bir FileStoreError ile başarısız olur (bkz. Dosya Depolama Hataları); reddedilen bir uygulamalar arası çağrı ise, tüketilen bir uygulamanın subscribeToTable çağrısı dahil, bir CrossAppAccessError ile başarısız olur. Bağlantıyı beklerken stop() tarafından sonlandırılan bir işlem, dışa aktarılan bir Error alt sınıfı olan ConnectionStoppedError ile başarısız olur. Bunun dışındaki her şey (hatalı parametreler, bağlantı olmaması) düz bir Error’dır.

Go’da başarısız bir işlem, mesajı işlemi ve nedeni belirten ve bu nedeni saran bir *ironflock.OperationError döndürür; errors.Is ve errors.As onun içini görür. Router’dan veya çağrılan taraftan gelen bir ret, URI, Args ve Kwargs alanlarına sahip bir *ironflock.WampError’dır (*wamp.Error); ironflock.WampURI(err) URI’yi ya da "" döndürür. Diğer sentinel hatalar ironflock.ErrMissingConfig (işlemin ihtiyaç duyduğu kimlik bilgisi eksik), ironflock.ErrAlreadyStarted ve wamp.ErrStopped’tur (Stop sonrasındaki bir işlem ya da Stop tarafından yarıda kesilen bir işlem).

Yükseltme: Eski Python ve JavaScript SDK sürümleri bir çağrı başarısız olduğunda bir mesaj kaydedip None / null döndürüyordu. Artık bunun yerine hata yükseltiyorlar; bu nedenle if result is None: biçimindeki kodlar hataları artık yakalamaz — try / except (ya da try / catch) kullanın.

Veri Arka Ucu Retleri

Veri arka ucunun reddettiği bir işlem, aşağıdaki WAMP hata URI’lerinden biriyle başarısız olur; neden ilk argümandadır. Üç SDK da bunları sabitler olarak dışa aktarır; Go bunları Go stilinde adlandırır (ironflock.URIRateLimited, ironflock.URIStorageFull, …). Python’da IronFlock metotları, nedeni autobahn’ın ApplicationError hatası olan bir RuntimeError yükseltir (tüketilen bir uygulamanın okumaları doğrudan ApplicationError yükseltir) ve wamp_error_uri(err) URI’yi her ikisinden de okur. JavaScript’te hata, error alanı URI olan bir WampError nesnesidir. Go’da bir *ironflock.WampError’ı saran bir *ironflock.OperationError’dır ve ironflock.WampURI(err) URI’yi okur. SDK’lar bunların hiçbirini yeniden denemez. Yayımlama metotları dahil her tablo yazması bunları bildirir: yayımlama metotları da ekleme yapar.

from datetime import datetime, timezone from ironflock import URI_STORAGE_FULL, wamp_error_uri row = {"tsp": datetime.now(timezone.utc).isoformat(), "temperature": 22.5} try: await ironflock.append_to_table("sensordata", row) except RuntimeError as err: if wamp_error_uri(err) == URI_STORAGE_FULL: pending.append(row) # the appliance's disk is nearly full: append the row later else: raise
SabitReddedilen
URI_RATE_LIMITEDBir cihazdaki uygulama kimlik bilgisi başına dakikada 30’u aşan revealSecrets / reveal_secrets ve 120’yi aşan verifySecret / verify_secret çağrıları
URI_RESULT_TOO_LARGE8 MiB’lık mesaj bütçesini aşan tek bir satır içeren bir okuma veya 1 GiB korumasını aşan bir sonuç (diğer büyük sonuçlar parçalar halinde gelir ve SDK bunları yeniden birleştirir). Anahtar kelime argümanları en büyük sütunları adlandırır: limit değerini düşürün, timeRange aralığını daraltın, daha az columns seçin veya columnPaths ile budayın
URI_INVALID_LIMITlimit değeri 3000’i aşan bir transform okuması
URI_INVALID_TIME_RANGE, URI_INVALID_METRIC, URI_INVALID_GROUP_BY, URI_SERIES_TOO_MANY_GROUPSTablonun yanıtlayamadığı seri sorguları: başlangıç yok veya bitiş başlangıçtan sonra değil; tablonun toplayamadığı bir metrik (böyle bir sütun yok, gizli bir sütun, sütun türünün kabul etmediği bir metot, COUNT dışında bir metotla tsp); tablonun gruplayamadığı bir groupBy sütunu; 50.000’den fazla satır
URI_SECRET_COLUMN, URI_NOT_A_SECRET_COLUMNGizli bir sütun üzerinde filtre; gizli olmayan bir sütun üzerinde verifySecret / verify_secret. Gizli sütunu olmayan bir tablonun açığa çıkarma veya doğrulama fonksiyonu hiç yoktur (bkz. revealSecrets)
URI_STORAGE_FULLAppliance’ın diski neredeyse doluyken yapılan bir ekleme (yaklaşık 3 GiB’ın altında boş alan; 4 GiB’tan itibaren yeniden kabul edilir) — geçicidir: satırları daha sonra ekleyin
URI_STORAGE_OVERUSAGEHesabın depolama hakkını aşan bir ekleme; kısa süre sonra yeniden denemek işe yaramaz
URI_ENTITY_KEY_CONFLICTVarlık anahtarı (maintainLatestFlagFor) ve tsp değeri, yığında veya saklanmış başka bir satırda zaten bulunan bir satır: her satıra kendi tsp değerini verin
URI_SECRET_SENTINEL_UNRESOLVABLE, URI_SECRET_CIPHERTEXT_REJECTEDBir sırrın önceki değerini (__secret__) onu bulacak bir varlık anahtarı olmadan koruyan bir yazma; zaten şifrelenmiş bir değerin yazılması

Veri arka ucunun neden belirtmeden reddettiği bir ekleme — wamp.error.runtime_error, tsp içermeyen bir satıra verdiği yanıt — türü belirli bir ret değildir: SDK’nın hata mesajı eksik tsp değerine ve veri arka ucunun nedeni kaydettiği, uygulamanın error-logs tablosuna işaret eder.

Tarayıcı Kullanımı (Yalnızca JavaScript)

JavaScript SDK modern tarayıcılarda çalışır. Tarayıcılarda ortam değişkenleri bulunmadığından, tüm yapılandırmayı yapıcı aracılığıyla geçin:

import { IronFlock } from "ironflock"; const ironflock = new IronFlock({ serialNumber: "device-serial-from-server", deviceKey: "12", appName: "MyWebApp", swarmKey: 10, appKey: 20, env: "PROD", }); await ironflock.start(); await ironflock.publishToTable("sensordata", [{ tsp: new Date().toISOString(), temperature: 22 }]);

Kimlik bilgilerini sabit kodlamak yerine arka ucunuzdan yapılandırma almak için IronFlock.fromServer()’ı kullanın:

const ironflock = await IronFlock.fromServer("/api/ironflock-config"); await ironflock.start();

Arka uç uç noktanız, bağlantı seçenekleriyle (serialNumber, deviceKey, appName, swarmKey, appKey, env) bir JSON nesnesi döndürmelidir.

AI Ajan Fonksiyonlarını Kaydetme

SDK, AI ajanları tarafından çağrılabilecek fonksiyonlar kaydedebilir. Bir prosedür kaydedin ve ai-template.yml dosyanızdaki konusunu referans alın:

def get_sensor_reading(sensor_id): """Returns the latest reading from a sensor.""" reading = read_from_hardware(sensor_id) return { "sensor_id": sensor_id, "temperature": reading.temp, "humidity": reading.hum, "timestamp": reading.ts } await ironflock.register_device_function("sensors.get_latest", get_sensor_reading)

AI ajanı, kullanıcı canlı sensör verisi gerektiren bir soru sorduğunda bu fonksiyonu çağırabilir.

Kayıtlı WAMP konusunu bir AI ajanına bağlamak için, uygulamanızın .ironflock/ai-template.yml dosyasında referans alın:

sensor_agent: tool_description: | Delegate to this agent when the user asks about sensor readings, live device data, or current environmental conditions. system_prompt: | You are a sensor data specialist. Use get_current to retrieve the latest reading from any sensor. Always include the unit in your response. main: true max_context_tokens: 30000 max_iterations: 5 tools: get_current: description: Returns the latest reading from a sensor. topic: sensors.get_latest parameters: sensor_id: type: string description: The sensor identifier to query. required: true

topic değeri (sensors.get_latest), edge kodunuzdaki register_device_function / registerDeviceFunction / RegisterDeviceFunction’a geçirilen adla eşleşmelidir. IronFlock, çağrıyı otomatik olarak fonksiyonun kaydedildiği cihaza yönlendirir.

Tam ai-template.yml referansı için bkz. Ajan & Araç Tanımlama.

Ortam Değişkenleri

Bu değişkenler IronFlock runtime tarafından uygulama container’ı içinde otomatik olarak ayarlanır:

DeğişkenAçıklama
DEVICE_NAMECihaz görüntülenme adı
DEVICE_SERIAL_NUMBERBenzersiz, değişmez cihaz tanımlayıcısı
DEVICE_KEYCihazın sayısal anahtarı. SDK, cihaz fonksiyonu URI’lerini ve uzaktan erişim tüneli etiketlerini bundan oluşturur ve onu yayımlarla ve tablo yazmalarıyla birlikte meta veri olarak gönderir; kimlik doğrulamak için onu kullanmaz
SWARM_KEYProje tanımlayıcısı
APP_KEYUygulama tanımlayıcısı
APP_NAMEUygulama adı
ENVOrtam: DEV veya PROD
APP_AUTH_ID, APP_AUTH_SECRETSDK’nın yönlendiriciye sunduğu, uygulamanın kendi kimlik bilgisi. Uygulamalar arası erişim bunu gerektirir; bu olmadan (eski bir cihaz ajanında) SDK cihaz seri numarasına geri döner
DEVICE_ENDPOINT_URLSDK’nın bağlandığı yönlendirici URL’si; yolu /ws-ua-usr ile değiştirilir. RESWARM_URL’ye tercih edilir; seçenek olarak geçilen bir yönlendirici URL’si (ironFlockUrl, Go’da WithURL) ikisini de geçersiz kılar
RESWARM_URLStudio URL’si; DEVICE_ENDPOINT_URL ayarlanmamışsa SDK yönlendirici URL’sini bundan türetir. SDK’nın tanımadığı bir studio URL’si start() / Start çağrısının başarısız olmasına yol açar. İki değişken de yoksa SDK wss://cbw.ironflock.com/ws-ua-usr adresine bağlanır
import os device_name = os.environ.get("DEVICE_NAME") serial = os.environ.get("DEVICE_SERIAL_NUMBER") project_key = os.environ.get("SWARM_KEY")

Uzaktan erişim değişkenleri (TUNNEL_DOMAIN, DEVICE_LAN_IP, DEVICE_PORT_FOR_<port>, REMOTE_PORT_FOR_<port>, …) Port Yapılandırma altında listelenmiştir.

Cihaz ajanı bu değerleri ayrıca /data/env altına, her biri için bir <NAME>.txt dosyası olacak şekilde yansıtır ve uygulama çalışırken bu yansımayı güncel tutar. SDK’lar, bir değişikliğin çalışan bir uygulamaya ulaşması için iki tür değeri önce dosyadan okur: her bağlantı denemesinde yeniden okunan uygulama başına kimlik bilgisi (APP_AUTH_ID, APP_AUTH_SECRET) — böylece ajanın uygulama çalışırken rotasyonla yenilediği bir kimlik bilgisi bir sonraki yeniden bağlanmada sunulur — ve getRemoteAccessUrlForPort her çağrıldığında okunan uzak portlar (REMOTE_PORT_FOR_<port> ve REMOTE_PORT_FOR_<port>_CLOUD). Diğer tüm değerler — kimlik (DEVICE_KEY, DEVICE_NAME, …), ENV ve tünel alan adları — container’ın başladığı andaki ortamdan gelir (Go, kimliği ve ENV değerini New içinde bir kez okur). Ajan /data/env dizinini yalnızca root tarafından okunabilir yapar: başka bir kullanıcı olarak çalışan bir container’da SDK, container’ın başladığı andaki değerleri görür ve bir kez uyarı kaydeder. JavaScript’te yansımayı okumak Node.js 22.3 veya üstünü gerektirir; daha eski bir Node.js yalnızca ortamı görür.

Last updated on