2016-07-08 23 views
5

मैं स्काला का उपयोग कर खेलो फ्रेमवर्क 2.3.x का उपयोग कर एक माइक्रो सेवा का निर्माण कर रहा हूँ स्ट्रीम कैसे (मैं दोनों में अभी शुरुआत कर रहा हूँ), लेकिन मैं अपने अनुरोध स्ट्रीम करने के लिए एक तरह से समझ नहीं तन। सरल परिवर्तन: मैं एक endpoint /transform जहाँ मैं एक बहुत बड़ा TSV फ़ाइल है कि मैं पार्स और एक अन्य प्रारूप में प्रस्तुत करना होगा प्राप्त कर सकते हैं की जरूरत हैप्ले फ्रेमवर्क स्काला: अनुरोध शरीर

:

यहाँ समस्या है। समस्या यह है कि मेरे नियंत्रक में प्रत्येक एकल आदेश "बहुत देर हो चुकी" है। यह कोड शुरू करने से पहले पूर्ण फ़ाइल प्राप्त करने की प्रतीक्षा करता है।

उदाहरण:

def transform = Action.async { 
    Future { 
     Logger.info("Too late") 
     Ok("A response") 
    } 
    } 

मैं के लिए फ़ाइल पूरी तरह से प्राप्त किए जाने का इंतजार किए बिना अनुरोध शरीर अपने अपलोड और प्रक्रिया पहले ही अनुरोध के दौरान पंक्ति-दर-पंक्ति को पढ़ने में सक्षम होना चाहता हूँ।

कोई संकेत स्वागत किया जाएगा।

+0

बहुखण्डीय फार्म-डेटा के रूप में अनुरोध शरीर पार्स। यह आपकी समस्या का समाधान हो सकता है। – Abhi

उत्तर

8

इस उत्तर 2.5.x और अधिक खेलने के लिए है, क्योंकि यह का उपयोग करता है अक्का धाराओं एपीआई कि उस संस्करण में खेलने के Iteratee आधारित स्ट्रीमिंग प्रतिस्थापित लागू होता है।

असल में, आप एक बॉडी पार्सर बना सकते हैं जो Source[T] देता है कि आप Ok.chunked(...) पर जा सकते हैं। एक तरह से यह करने के लिए शरीर पार्सर में Accumulator.source[T] उपयोग करने के लिए है। उदाहरण के लिए, एक कार्रवाई है कि शब्दशः यह करने के लिए भेजा सिर्फ दिए गए डेटा इस प्रकार दिखाई देंगे:

def verbatimBodyParser: BodyParser[Source[ByteString, _]] = BodyParser { _ => 
    // Return the source directly. We need to return 
    // an Accumulator[Either[Result, T]], so if we were 
    // handling any errors we could map to something like 
    // a Left(BadRequest("error")). Since we're not 
    // we just wrap the source in a Right(...) 
    Accumulator.source[ByteString] 
    .map(Right.apply) 
} 

def stream = Action(verbatimBodyParser) { implicit request => 
    Ok.chunked(request.body) 
} 

आप स्रोत, जैसे को बदलने के लिए TSV फ़ाइल को बदलने की तरह कुछ आप एक Flow उपयोग कर सकते हैं करना चाहते हैं तो:

val tsvToCsv: BodyParser[Source[ByteString, _]] = BodyParser { req => 

    val transformFlow: Flow[ByteString, ByteString, NotUsed] = Flow[ByteString] 
    // Chunk incoming bytes by newlines, truncating them if the lines 
    // are longer than 1000 bytes... 
    .via(Framing.delimiter(ByteString("\n"), 1000, allowTruncation = true)) 
    // Replace tabs by commas. This is just a silly example and 
    // you could obviously do something more clever here... 
    .map(s => ByteString(s.utf8String.split('\t').mkString(",") + "\n")) 

    Accumulator.source[ByteString] 
    .map(_.via(transformFlow)) 
    .map(Right.apply) 
} 

def convert = Action(tsvToCsv) { implicit request => 
    Ok.chunked(request.body).as("text/csv") 
} 

Play दस्तावेज़ों के Directing the Body Elsewhere अनुभाग में और अधिक प्रेरणा हो सकती है।

+0

धन्यवाद! मुझे पहले से ही पता चला है कि यह उन चीजों को बनाने का मुद्दा है जिन्हें मैं Play 2.3.x पर काम करना चाहता हूं। लेकिन मैं शायद 2.5.x पर मज़ा के लिए यह कोशिश करूँगा। – Cecile

संबंधित मुद्दे