2017-12-29 50 views
0

나는 내 자신의 WebSocket 프로토콜을 만들고 텍스트 키/값 헤더 부분을 가지며 2 개의 연속 된 개행과 2 진 꼬리가 끝나는 것으로 생각합니다.2 바이트 구분 기호로 akka ByteString을 분할하는 방법

밝혀졌습니다. ByteString을 두 줄로 나누는 것은 정말 지루합니다. 하나는 내장 된 .split 메소드가 없습니다. 그리고 이진 지문을 찾는 데는 .indexOf이 없습니다.

무엇을 사용 하시겠습니까? 그런 프로토콜을 만드는 더 쉬운 방법이 있습니까?

참고 :

  • akka-HTTP 10.1.0-RC1을 사용

ByteString akka, akka 2.5.8

+0

복사/재사용 할 수있는 akka-http 소스 코드에 (내부) 스트리밍 LineParser가 있습니다. https://github.com/akka/akka-http/blob/86c56ab41c595b739f36b30bbf3135cdb7e45bba/akka-http/src/main/scala/akka/http/scaladsl/unmarshalling/sse/LineParser.scala#L25 – jrudolph

답변

0

나는이 함께했다. 실제로 그것을 테스트하지 않았습니다.

@tailrec 
def peelMsg(bs: ByteString, accHeaderLines: Seq[String]): Tuple2[Seq[String],ByteString] = { 

    val (a: ByteString, tail: ByteString) = bs.span(_ != '\n') 
    val b: ByteString = tail.drop(1) 

    if (a.isEmpty) { // end marker - empty line 
    Tuple2(accHeaderLines,b) 
    } else { 
    val acc: Seq[String] = accHeaderLines :+ a.utf8String // append 
    peelMsg(b,acc) 
    } 
} 

val (headerLines: Seq[String], value: ByteString) = peelMsg(bs,Seq.empty) 
+0

사용하지 마십시오. . 재귀 적으로 진행할 필요는 없습니다. 더 좋은 아이디어가 주위에있는 것처럼 보이지만, 토론을 위해서 여기에 남겨두고 있습니다. – akauppi

1

하나 개의 접근법은 우선 ByteString의 indexedSeq에서 쌍 슬라이딩 생성하는 것, 다음 예에서와 같이 분리 쌍의 식별 인덱스를 사용 ByteString 분할 :

import akka.util.ByteString 

val bs = ByteString("aa\nbb\n\nxyz") 
// bs: akka.util.ByteString = ByteString(97, 97, 10, 98, 98, 10, 10, 120, 121, 122) 

val delimiter = 10 

// Create sliding pairs from indexedSeq of the ByteString 
val slidingList = bs.zipWithIndex.sliding(2).toList 
// slidingList: List[scala.collection.immutable.IndexedSeq[(Byte, Int)]] = List(
// Vector((97,0), (97,1)), Vector((97,1), (10,2)), Vector((10,2), (98,3)), 
// Vector((98,3), (98,4)), Vector((98,4), (10,5)), Vector((10,5), (10,6)), 
// Vector((10,6), (120,7)), Vector((120,7), (121,8)), Vector((121,8), (122,9)) 
//) 

// Get indexes of the delimiter-pair 
val dIndex = slidingList.filter{ 
    case Vector(x, y) => x._1 == delimiter && y._1 == delimiter 
}.flatMap{ 
    case Vector(x, y) => Seq(x._2, y._2) 
} 

// Split the ByteString list 
val (bs1, bs2) = (bs.splitAt(dIndex(0))._1, bs.splitAt(dIndex(1))._2.tail) 
// bs1: akka.util.ByteString = ByteString(97, 97, 10, 98, 98) 
// bs2: akka.util.ByteString = ByteString(120, 121, 122) 
0

내 지금 코드 : @ 레오-C의 대답의 영향을

// Find the index of the (first) double-newline 
// 
val n: Int = { 
    val bsLen: Int = bs.length 

    val tmp: Int = bs.zipWithIndex.find{ 
    case ('\n',i) if i<bsLen-1 && bs(i+1)=='\n' => true 
    case _ => false 
    }.map(_._2).getOrElse{ 
    throw new RuntimeException("No delimiter found") 
    } 
    tmp 
} 

val (bs1: ByteString, bs2: ByteString) = bs.splitAt(n) // headers, \n\n<binary> 

하지만, 슬라이딩 윈도우 대신 일반 .find를 사용하여. ByteString이 랜덤 액세스를 허용하기 때문에, 나는 그 조건으로 스트리밍 검색을 결합 할 수 있다는 것을 깨달았다.