ट्रैसलेट सिंक: द नेटवर्क स्टोरी
यदि डेटा आपके सर्वर तक कभी नहीं पहुंचता है तो स्थान ट्रैकिंग का कोई मतलब नहीं है। मोबाइल डिवाइस लगातार कनेक्शन बंद कर देते हैं - लिफ्ट में प्रवेश करते समय, घाटियों के माध्यम से गाड़ी चलाते समय, या वाई-फ़ाई से सेल्युलर पर स्विच करते समय। ट्रैसलेट सिंक एक ऑफ़लाइन-प्रथम, बैटरी-अवेयर नेटवर्किंग इंजन है जिसे यूआई को सक्रिय किए बिना डेटा डिलीवरी सुनिश्चित करने के लिए डिज़ाइन किया गया है।
ट्रैसलेट 3.2.0 अपडेट: HTTP सिंक लॉजिक को tracelet_sync मॉड्यूल में ले जाया गया है। यदि आपको नेटवर्क सिंक्रनाइज़ेशन की आवश्यकता है तो आपको यह मॉड्यूल शामिल करना होगा।
नेटवर्क से कैसे सिंक करें
जबकि ट्रैसलेट कोर स्थानों को कैप्चर करता है, tracelet_sync पृष्ठभूमि HTTP इंजन है जो उन्हें आपके सर्वर तक पहुंचाता है। इसे सक्षम करने के लिए, ट्रैकिंग शुरू करने से पहले TraceletSync.ready() प्रारंभ करें:
import 'package:tracelet_sync/tracelet_sync.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// 1. Configure the Sync Engine
await TraceletSync.ready(SyncConfig(
url: 'https://your-api.com/locations',
method: 'POST',
autoSyncThreshold: 10, // Sync every 10 locations
autoSyncDelay: 10000, // Wait 10s before pushing
syncInterval: 0, // (Optional) Seconds between repeating queue flushes; 0 = off
batchSync: true, // Send as a JSON array
maxBatchSize: 250, // Up to 250 locations per request
headers: {
'Authorization': 'Bearer YOUR_TOKEN'
},
));
// 2. Configure and start Tracelet Core as usual
await Tracelet.ready(Config.balanced());
await Tracelet.start();
}एक बार कॉन्फ़िगर हो जाने पर, इंजन नीचे दिए गए सभी परिदृश्यों को स्वचालित रूप से संभाल लेगा!
परिदृश्य 1: पर्वतारोहण
अवधारणाओं की खोज: ऑफ़लाइन कतार, बैच सिंक, डिबाउंसिंग
समस्या
पहाड़ों के बीच 3 घंटे की पैदल यात्रा को ट्रैक करने के लिए मार्क आपके फिटनेस ऐप का उपयोग कर रहा है। उसके पास शून्य सेलुलर सेवा है। यदि आपका ऐप हर बार एक कदम उठाने पर HTTP POST का प्रयास करता है, तो यह विफल हो जाएगा, सिग्नल की खोज में बैटरी बर्बाद हो जाएगी, और स्थान बिंदु हमेशा के लिए खो जाएंगे। जब वह अंततः अपनी कार में वापस आएगा, तो उसका मार्ग एक खाली मानचित्र जैसा दिखाई देगा।
ट्रैसलेट सिंक इसे कैसे हल करता है
-
ऑफ़लाइन SQLite दृढ़ता (
autoSyncThreshold) क्योंकि मार्क के पास कोई सिग्नल नहीं है, ट्रैसलेट तुरंत HTTP अनुरोध भेजने का प्रयास करना बंद कर देता है। इसके बजाय, प्रत्येक स्थान को स्थानीय SQLite डेटाबेस में सुरक्षित रूप से संग्रहीत किया जाता है। हमनेautoSyncThreshold: 100सेट किया है, जिसका अर्थ है कि ट्रैसलेट नेटवर्क रेडियो को जगाने का प्रयास भी नहीं करेगा जब तक कि डेटाबेस में कम से कम 100 अंक कतारबद्ध न हो जाएं। -
विवादास्पद सिंकिंग (
autoSyncDelay) जब मार्क अंततः पहाड़ से नीचे चला गया और 4G पुनः प्राप्त कर लिया, तो उसके पास अचानक 500 कतारबद्ध स्थान थे। 500 तत्काल HTTP अनुरोधों को सक्रिय करने के बजाय (जिससे उसका फ़ोन फ़्रीज़ हो जाएगा),autoSyncDelay: 10000ट्रैसलेट को 10 सेकंड प्रतीक्षा करने के लिए कहता है। यह डेटा के तीव्र प्रवाह को रोकता है, जिससे कनेक्शन स्थिर हो जाता है। -
बैच सिंकिंग (
batchSyncऔरmaxBatchSize) 500 व्यक्तिगतPOSTअनुरोधों के बजाय,batchSync: trueऔरmaxBatchSize: 250स्थानों को दो विशाल JSON सरणियों में बंडल करते हैं। यह पहले 250 अंक भेजता है, आपके सर्वर द्वाराHTTP 200 OKलौटाने की प्रतीक्षा करता है, SQLite से उन बिंदुओं को हटा देता है, और फिर अगला बैच भेजता है। -
अंतराल-आधारित सिंक (
syncInterval)autoSyncDelayनए स्थानों पर प्रतिक्रिया करता है। यदि आप भी समय-संचालित फ्लश चाहते हैं - एक निश्चित ताल पर जो कुछ भी पंक्तिबद्ध है उसे अपलोड करना, भले ही कितने अंक जमा हुए हों - फ्लश के बीच सेकंड की संख्या परsyncIntervalसेट करें (उदाहरण के लिएsyncInterval: 60ऑफ़लाइन कतार को एक मिनट में एक बार फ्लश करता है)। यह डिबाउंस के साथ-साथ चलता है और डिफ़ॉल्ट रूप से अक्षम है (0)।
परिदृश्य 2: कैफ़े वाई-फ़ाई से कनेक्ट करना
अवधारणाओं की खोज: सेलुलर प्रतिबंध, डेल्टा संपीड़न
समस्या
मार्क अपनी पदयात्रा पूरी करता है और एक कैफे में जाता है। वह अंतरराष्ट्रीय स्तर पर यात्रा कर रहा है, इसलिए उसका सेल्युलर डेटा प्लान बेहद महंगा है। आपके ऐप ने मेगाबाइट लोकेशन JSON डेटा को कतारबद्ध कर दिया है, और इसे अपने रोमिंग 4G कनेक्शन पर भेजने पर उसके पैसे खर्च होंगे।
ट्रैसलेट सिंक इसे कैसे हल करता है
-
सेलुलर प्रतिबंध (ट्रांस0 देर से नहीं)
disableAutoSyncOnCellular: trueसेट करके, ट्रैसलेट सिंक इंजन को पूरी तरह से ब्लॉक कर देता है जबकि मार्क 4जी पर है। SQLite में स्थान सुरक्षित रहते हैं। जैसे ही वह कैफे के वाई-फाई से जुड़ता है, ओएस ट्रैसलेट को सक्रिय कर देता है और सिंक इंजन स्वचालित रूप से कतार को फ्लश कर देता है। -
डेल्टा एन्कोडिंग संपीड़न (
enableDeltaCompression) वाई-फ़ाई पर भी, बड़े पैमाने पर JSON ऐरे भेजना धीमा है। बैच भेजने से पहले ट्रेसलेट डेल्टा कम्प्रेशन लागू करता है। यदि मार्क एक सीधी रेखा में चलता, तो उसके अक्षांश में अधिक परिवर्तन नहीं होता। प्रत्येक बिंदु के लिए पूर्ण निर्देशांक भेजने के बजाय, ट्रैसलेट पहले बिंदु को पूर्ण रूप से भेजता है, और उसके बाद बाद के बिंदुओं के लिए केवल अंतर (डेल्टा) भेजता है।deltaCoordinatePrecision: 5(~1.1 मीटर तक सटीक) के साथ, यह HTTP पेलोड आकार को 60% से 80% तक कम कर देता है।
मानक पेलोड (कोई संपीड़न नहीं):
[
{"lat": 37.774900, "lng": -122.419400},
{"lat": 37.774910, "lng": -122.419410},
{"lat": 37.774920, "lng": -122.419420}
]डेल्टा एनकोडेड पेलोड (आपका सर्वर क्या प्राप्त करता है):
[
{"lat": 37.774900, "lng": -122.419400},
{"dLat": 10, "dLng": 10},
{"dLat": 10, "dLng": 10}
]परिदृश्य 3: समाप्त सत्र
अवधारणाओं की खोज: 401 पुनर्प्रयास, हेडलेस कॉलबैक, घातीय बैकऑफ़
समस्या
मार्क का ऑथ टोकन (JWT) तब समाप्त हो गया जब वह पदयात्रा कर रहा था। जब ट्रैसलेट अंततः बैच को आपके सर्वर से सिंक करने का प्रयास करता है, तो आपका एपीआई एक HTTP 401 Unauthorized लौटाता है। एक अनुभवहीन सिंक इंजन या तो डेटा को यह सोचकर हटा देगा कि यह विफल हो गया है, या 401s के अनंत लूप में फंस जाएगा, जिससे बैटरी खत्म हो जाएगी। मार्क का फ़ोन उसकी जेब में है और स्क्रीन बंद है—वह अभी लॉग इन नहीं कर सकता।
ट्रैसलेट सिंक इसे कैसे हल करता है
- डायनेमिक हेडर कॉलबैक जब ट्रैसलेट को 401 प्राप्त होता है, तो उसे पुनः प्रयास करने से पहले एक नया टोकन प्राप्त करना होगा। आप इसे अग्रभूमि और पृष्ठभूमि (हेडलेस) दोनों स्थितियों में संभालने के लिए कॉलबैक पंजीकृत करते हैं।
फोरग्राउंड कॉलबैक:
tl.Tracelet.setHeadersCallback(() async {
final newJwt = await AuthAPI.refreshToken();
return {'Authorization': 'Bearer $newJwt'};
});पृष्ठभूमि (बिना सिर के) कॉलबैक: यह आपके यूआई को सक्रिय किए बिना एक अलग डार्ट इंजन में चलता है, जिससे यह सुनिश्चित होता है कि उपयोगकर्ता द्वारा ऐप छोड़ने पर भी सिंकिंग काम करती है।
@pragma('vm:entry-point')
void headlessHeadersCallback(tl.HeadlessEvent event) async {
final newJwt = await AuthAPI.refreshToken();
tl.Tracelet.setDynamicHeaders({'Authorization': 'Bearer $newJwt'});
}
// Register it before runApp()
tl.Tracelet.registerHeadlessHeadersCallback(headlessHeadersCallback);- एक्सपोनेंशियल बैकऑफ़ (
maxRetriesऔरretryBackoffCap) यदि आपका प्रमाणीकरण सर्वर डाउन हो और 503 लौटाए तो क्या होगा? ट्रैसलेट इसे खूबसूरती से संभालता है। यह पुनः प्रयास का प्रयास करता है। यह विफल रहा। यह 1 सेकंड (retryBackoffBase) प्रतीक्षा करता है, फिर 2 सेकंड, फिर 4 सेकंड। घातीय बैकऑफ़ 60 सेकंड (retryBackoffCap) पर सीमित है। 3 प्रयासों (maxRetries) के बाद, यह पूरी तरह से हार मान लेता है, कल फिर से प्रयास करने के लिए डेटा को SQLite में सुरक्षित रूप से छोड़ देता है।
परिदृश्य 4: कस्टम सर्वर स्कीमा
अवधारणाओं की खोज: कस्टम सिंक बॉडी बिल्डर्स, स्कीमा मैपिंग
समस्या
मार्क की कंपनी के पास एक विरासती बैकएंड है जो बहुत विशिष्ट, गैर-मानक प्रारूप में स्थान डेटा की अपेक्षा करता है। ट्रैसलेट का डिफ़ॉल्ट JSON पेलोड उनके सर्वर की आवश्यक स्कीमा से मेल नहीं खाता है, और वे केवल इस ऐप के लिए बैकएंड एपीआई को नहीं बदल सकते हैं।
ट्रैसलेट सिंक इसे कैसे हल करता है
- कस्टम सिंक बॉडी बिल्डर (
setSyncBodyBuilder) डिफ़ॉल्ट JSON रैपर का उपयोग करने के बजाय, ट्रैसलेट आपको नेटवर्क पर भेजे जाने से ठीक पहले स्थानों के बैच को इंटरसेप्ट करने देता है, जिससे आप उन्हें अपने सर्वर की इच्छानुसार किसी भी आकार में मैप कर सकते हैं।
ट्रेसलेट 3.2.8 से शुरू होकर, इस बिल्डर को दिए गए स्थान एक मजबूत नेस्टेड स्कीमा का उपयोग करते हैं (जहां निर्देशांक coords के तहत सुरक्षित रूप से समूहीकृत होते हैं और activity के तहत गतिविधि डेटा)।
Tracelet.setSyncBodyBuilder((context) async {
// Map Tracelet's nested schema to your legacy server's flat schema
final mappedPoints = context.locations.map((loc) {
final coords = loc['coords'] as Map;
final activity = loc['activity'] as Map;
return {
'lat': coords['latitude'],
'lng': coords['longitude'],
'time': loc['timestamp'],
'moving': loc['is_moving'],
'action': activity['type'],
};
}).toList();
// Return the exact JSON structure your server expects
return {
'device_id': myDeviceId,
'payload': mappedPoints,
};
});- बिना सिर के फांसी
टोकन रिफ्रेश की तरह, इस कस्टम बॉडी बिल्डिंग को भी
registerHeadlessSyncBodyBuilder()के माध्यम से पृष्ठभूमि में पूरी तरह से हेडलेस रूप से निष्पादित किया जा सकता है, यह सुनिश्चित करते हुए कि ऐप पूरी तरह से समाप्त होने पर भी आपका कस्टम स्कीमा बनाया और भेजा जाता है।
परिदृश्य 5: डिलीवरी ड्राइवर
अवधारणाओं की खोज: मार्ग संदर्भ और व्यावसायिक तर्क इंजेक्शन
समस्या
आपके बैकएंड को हजारों कच्चे निर्देशांक प्राप्त होते हैं। लेकिन अकेले निर्देशांक आपको यह नहीं बताता कि उपयोगकर्ता वहां क्यों था। क्या ड्राइवर डिलीवरी कार्य पर था? वे कौन सा ऑर्डर डिलीवर कर रहे थे? आपको व्यावसायिक तर्क को सीधे पृष्ठभूमि स्थान पेलोड से जोड़ने का एक तरीका चाहिए ताकि आप इसे आसानी से अपने डेटाबेस में क्वेरी कर सकें।
ट्रैसलेट सिंक इसे कैसे हल करता है
-
रूट संदर्भ निर्धारित करना आप कस्टम मेटाडेटा को ट्रैसलेट में इंजेक्ट कर सकते हैं। आपके द्वारा
setRouteContext()पर कॉल करने के बाद रिकॉर्ड किया गया प्रत्येक स्थान स्वचालित रूप से आंतरिक SQLite डेटाबेस में इस डेटा के साथ स्थायी रूप से टैग किया जाएगा।await tl.Tracelet.setRouteContext( const tl.RouteContext( taskId: 'delivery-1234', driverId: 'john_doe', custom: {'shift_id': 'morning-shift-001'}, ), ); -
परिणामस्वरूप JSON पेलोड जब ट्रैसलेट आपके बैकएंड से सिंक होता है, तो सरणी के प्रत्येक स्थान में
contextऑब्जेक्ट शामिल होगा, जिससे यह गारंटी होगी कि आपका बैकएंड ठीक से जानता है कि यह स्थान किस कार्य से संबंधित है।{ "locations": [ { "coords": { "latitude": 37.7749, "longitude": -122.4194 }, "battery": { "level": 0.85, "isCharging": true }, "extras": { "your_custom_key": "your_value" }, "context": { "taskId": "delivery-1234", "driverId": "john_doe", "custom": { "shift_id": "morning-shift-001" } } } ] }
बैटरी स्थिति ट्रैकिंग
ट्रेसलेट को कठोर, ऑफ़लाइन वातावरण के लिए डिज़ाइन किया गया है जहां डिवाइस किसी स्थान को रिकॉर्ड किए जाने के कुछ घंटों बाद सिंक हो सकते हैं। फ़ील्ड में डिवाइस की स्थिति को समझने में आपकी मदद करने के लिए, ट्रैसलेट प्रत्येक स्थान को रिकॉर्ड किए जाने के समय स्वचालित रूप से सटीक बैटरी स्थिति को कैप्चर करता है।
इसके लिए शून्य कॉन्फ़िगरेशन की आवश्यकता है:
- इंजन
level(उदाहरण के लिए 85% के लिए 0.85) औरisChargingस्थिति को कैप्चर करता है। - यह स्थिति जीपीएस निर्देशांक के साथ ऑफ़लाइन SQLite डेटाबेस में सुरक्षित रूप से सहेजी गई है।
- जब डिवाइस वापस ऑनलाइन आता है, तो सिंक इंजन सटीक ऐतिहासिक बैटरी स्थिति को प्रसारित करता है, वर्तमान बैटरी स्थिति को नहीं।
यह आपके बैकएंड को किसी मार्ग पर बैटरी खत्म होने की सटीक कल्पना करने या यह पहचानने की अनुमति देता है कि ड्राइवर शिफ्ट के दौरान लगातार अपने डिवाइस को अनप्लग कर रहे हैं या नहीं।
-
संदर्भ साफ़ करना जब ड्राइवर अपनी डिलीवरी पूरी कर ले, तो संदर्भ साफ़ करें। इसके बाद के स्थानों को अब टैग नहीं किया जाएगा.
await tl.Tracelet.clearRouteContext();
आप सिंक करने से पहले इस संदर्भ के आधार पर आंतरिक SQLite डेटाबेस से क्वेरी भी कर सकते हैं:
// Get all locations belonging to a specific delivery task
final locations = await tl.Tracelet.getLocations(
tl.SQLQuery(where: "context_task_id = 'delivery-1234'")
);