HTTP Yönlendirmeleri
PlainApp, POST /graphql adresindeki GraphQL API'sinin yanında küçük bir HTTP uç noktası seti sunar. Bu uç noktalar dosya sunma, multipart yüklemeler, zip akışı, DLNA yayınlama, WebSocket olayları ve sistem kontrolünü ele alır. Tüm file/upload/zip uç noktaları c-id başlığı (ve genellikle şifrelenmiş bir id sorgu parametresi) gerektirir.
Tip Tanımları
# Common headers for protected HTTP endpoints:
c-id: <client-id>
# /fs, /proxyfs, /zip/* use an encrypted "id" query parameter produced
# by the GraphQL files()/fileIds() queries. The id is opaque to the client.
# Upload endpoints additionally require an encrypted "info" multipart part:
# info = chaCha20Encrypt(token, json({ dir, size, replace, isAppFile }))
# file = <raw bytes>
# Chunked uploads use:
# info = chaCha20Encrypt(token, json({ fileId, index, size }))
# Status codes follow HTTP semantics:
# 200 OK – success
# 201 Created – upload stored
# 204 No Content – init pending password
# 400 Bad Request – missing/invalid params
# 401 Unauthorized – bad token
# 403 Forbidden – expired/invalid encrypted id
# 404 Not Found – file/entry missing
# 410 Gone – server shutting down
# 429 Too Many Requests – concurrent zip limit hitİşlemler
POST /graphql
Ana GraphQL uç noktası. Tüm GraphQL sorgularını ve mutasyonlarını c-id + Authorization başlıklarıyla buraya gönderin. /peer_graphql uç noktası, eşleştirilmiş cihazlar arasında kullanılan peer-to-peer eşdeğeridir.
curl --request POST \
--url http://192.168.1.100:8080/graphql \
--header 'c-id: <client-id>' \
--header 'Authorization: Bearer <api-token>' \
--header 'Content-Type: application/json' \
--data '{"query":"{ app { battery deviceName } }"}'GET /fs
Bir dosya, content:// URI'si veya paket simgesi sunar. id sorgu parametresi, files()/fileIds() tarafından döndürülen şifrelenmiş bir dizedir. Küçük resim oluşturma (?w=&h=&cc=), düşük verimli taşımalar için bayt aralığı (?offset=&length=), HEIF→PNG dönüştürme, 3gp→MP4 transkodlama ve bir Content-Disposition attachment başlığıyla indirme modunu (dl=1) destekler.
# Original (full size, inline)
curl http://192.168.1.100:8080/fs?id=<encrypted-id> -o file.jpg
# Thumbnail (center-cropped to 200x200)
curl 'http://192.168.1.100:8080/fs?id=<encrypted-id>&w=200&h=200' -o thumb.jpg
# Download (attachment)
curl 'http://192.168.1.100:8080/fs?id=<encrypted-id>&dl=1' -OJ
# Byte range (BLE chunked download)
curl 'http://192.168.1.100:8080/fs?id=<encrypted-id>&offset=0&length=4096' \
-o chunk.binGET /proxyfs
Bir peer HTTP URL'sini vekil sunar. id sorgu parametresi, eşleştirilmiş bir peer cihazdaki tam bir http(s) URL'sine çözülür; sunucu upstream yanıtını geri akıtır. Wi-Fi Aware üzerinden peer-to-peer dosya indirmeleri için kullanılır.
curl http://192.168.1.100:8080/proxyfs?id=<encrypted-peer-url> -o peer-file.jpgPOST /upload
multipart/form-data aracılığıyla tek bir dosya yükleyin. "info" kısmı (ChaCha20 ile şifrelenmiş JSON), "file" kısmından önce gelmelidir. isAppFile=true olduğunda baytlar content-addressable AppFileStore'a (hash'e göre deduplikasyon) içe aktarılır; aksi takdirde dosya info.dir/<fileName> konumuna yazılır. Son dosya adını döndürür (üzerine yazmaktan kaçınırken bir "(1)" son eki olabilir).
curl --request POST \
--url http://192.168.1.100:8080/upload \
--header 'c-id: <client-id>' \
--form 'info=<encrypted-info-bytes>;type=application/octet-stream' \
--form 'file=@/path/to/local.jpg'POST /upload_chunk
Devam ettirilebilen, parçalı bir yükleme için bir parça yükleyin. Her parça diske upload_tmp/{fileId}/chunk_{index} konumuna yazılır. "<index>:<savedSize>" döndürür. Tüm parçalar geldikten sonra, son dosyayı birleştirmek için mergeChunks GraphQL mutasyonunu çağırın.
curl --request POST \
--url http://192.168.1.100:8080/upload_chunk \
--header 'c-id: <client-id>' \
--form 'info=<encrypted-chunk-info-bytes>;type=application/octet-stream' \
--form 'file=@/path/to/chunk_0.bin'GET /zip/dir
Tek bir dizini zip arşivi olarak akıtın. id sorgu parametresi bir dizin yoluna çözülür. Cihazda aynı anda yalnızca bir zip işlemi çalışır — eşzamanlı istekler HTTP 429 alır.
curl 'http://192.168.1.100:8080/zip/dir?id=<encrypted-dir-id>' \
-o folder.zipGET /zip/files
Birden fazla dosyayı (veya medya arama sonuçlarını) tek bir zip olarak akıtın. id, { type, query, id, name } değerine çözülür. FILE tipi için dosya listesi files() GraphQL sorgusu tarafından TempHelper içinde request.id altında saklanır; medya tipleri için sunucu searchZipItems(type, query, id) çalıştırır.
curl 'http://192.168.1.100:8080/zip/files?id=<encrypted-request>' \
-o selection.zipGET /media/{id}
DLNA medya uç noktası. Daha önce kaydedilmiş bir medya yolunu (UrlHelper.getMediaHttpUrl ile kaydedilmiş) bir TV / DLNA renderer'ına sunar. URL kaynakları vekil sunulur, content:// URI'leri akıtılır, görseller olduğu gibi sunulur ve diğer tüm dosyalar renderer'ların akışı kabul etmesi için DLNA'ya özgü başlıklar + HTTP 206 range desteğiyle sunulur.
# Play on a DLNA renderer:
curl http://192.168.1.100:8080/media/<id>.mp4 -o video.mp4NOTIFY /callback/cast
DLNA renderer geri araması. Renderer'ın olay NOTIFY XML'ini alır ve CastPlayer durumunu günceller. TransportState=STOPPED'da (AVTransportURIMetaData olmadan) oynatıcı otomatik olarak çalma listesindeki bir sonraki öğeye geçer. Konum güncellemeleri için RelTime / TrackDuration'ı da ayrıştırır.
# Sent by the DLNA renderer (not by the client):
NOTIFY /callback/cast HTTP/1.1
Content-Type: text/xml
<?xml ...><e:propertyset>...TransportState val="PLAYING"...</e:propertyset>GET /health
Kimlik doğrulaması gerektirmeyen sağlık kontrolü uç noktası. Uygulama paketi adını düz metin olarak döndürür. HTTP sunucusunun erişilebilir olduğunu doğrulamak için bunu kullanın.
curl http://192.168.1.100:8080/healthGET /shutdown
HTTP sunucusunu kapatır. Yalnızca localhost'tan çağrılabilir — uzak istekler HTTP 403 alır. Tüm WebSocket oturumlarını kapatır, çevrimiçi istemci setini temizler ve HTTP sunucusunu dispose eder.
# Must be run on the device (e.g. via adb shell):
curl http://localhost:8080/shutdownPOST /init
Bir istemci oturumu başlatır. c-id başlığı gerektirir. Geçerli bir şifrelenmiş gövde mevcutsa (önbelleğe alınmış token ile çözülür), oturum kimliği doğrulanmış sayılır ve sunucu 200 yanıtlar. Aksi takdirde: parola ayarlanmadıysa, sunucu yeni sıfırlanmış bir parolayla yanıt verir (200); parola ayarlanmışsa, 204 No Content yanıt verir ve istemci WebSocket giriş akışı üzerinden kimlik doğrulaması yapmalıdır.
curl --request POST \
--url http://192.168.1.100:8080/init \
--header 'c-id: <client-id>' \
--data-binary '<encrypted-token-bytes>'WS /
Ana WebSocket uç noktası. Bir oturum kaydetmek için ?cid=<client-id> kullanın; ilk binary çerçeve şifrelenmiş bir timestamp (veya ?auth=1 ile parolayı içeren şifrelenmiş bir AuthRequest) olmalıdır. Kimlik doğrulamadan sonra sunucu, bu soket üzerinden şifrelenmiş olay çerçeveleri (bildirimler, sohbet güncellemeleri vb.) gönderir.
# Browser / JS example
const ws = new WebSocket('ws://192.168.1.100:8080/?cid=<client-id>')
ws.binaryType = 'arraybuffer'
ws.send(encryptWithToken(token, Date.now().toString()))
// Login variant:
const ws = new WebSocket('ws://192.168.1.100:8080/?cid=<client-id>&auth=1')
ws.send(encryptWithPassword(password, JSON.stringify({ password: hash })))WS /status
Peer varlık WebSocket'i. Eşleştirilmiş bir peer'ı çevrimiçi olarak işaretli tutmak için ?cid=<peer-id> kullanın. İlk binary çerçeve PeerChatParser ile şifrelenmiş bir istek olmalıdır; başarı durumunda sunucu "ok" metni gönderir ve soket kapanana kadar peer'ı çevrimiçi olarak işaretler.
# Peer-to-peer keepalive (typically opened automatically by the chat
# client after pairing — not usually invoked manually)
const ws = new WebSocket('ws://192.168.1.100:8080/status?cid=<peer-id>')
ws.send(peerEncryptedFrame)