I am parsing a GftsRealtime feed using google protobuf parser. Here is the exact error I am encountering:
com.google.protobuf.InvalidProtocolBufferException: While parsing a protocol message, the input ended unexpectedly in the middle of a field. This could mean either than the input has been truncated or that an embedded message misreported its own length.
First thought that comes to mind is that the integrity of the file was compromised while downloading but I check the file in the Android emulator against the one I download on the desktop and it's the same. Has anyone encountered this issue before? I am using version '0.0.4' of the gfts-realtime-parser. The feed is here.
EDIT ----
Here is the code I use to download the file:
override fun doInBackground(vararg urls: URL): Boolean? {
val httpClient = OkHttpClient()
val call = httpClient.newCall(Request.Builder().url(urls[0]).get().build())
val urlStr = urls[0].toString()
val fileName = urlStr.substring(urlStr.lastIndexOf('/') + 1, urlStr.length)
val file = File(context.filesDir, fileName)
try {
val response = call.execute()
if (response.code() === 200) {
var inputStream: InputStream? = null
val outputStream = FileOutputStream(file)
try {
inputStream = response.body().byteStream()
val buff = ByteArray(1024 * 4)
var downloaded: Long = 0
val target = response.body().contentLength()
publishProgress(0L, target)
while (true) {
val readed = inputStream!!.read(buff)
if (readed == -1) {
break
}
outputStream.write(buff, 0, readed)
//write buff
downloaded += readed.toLong()
publishProgress(downloaded, target)
if (isCancelled()) {
fileListener(null)
return false
}
}
fileListener(file)
return downloaded == target
} catch (ignore: IOException) {
fileListener(null)
return false
} finally {
if (inputStream != null) {
inputStream!!.close()
}
outputStream.flush()
outputStream.close()
}
} else {
fileListener(null)
return false
}
} catch (e: Exception) {
e.printStackTrace()
fileListener(null)
return false
}
}
EDIT 2 ---- Here is the complete code path
override fun onHandleIntent(intent: Intent?) {
Realm.init(applicationContext)
val config = RealmConfiguration.Builder().deleteRealmIfMigrationNeeded().build() // TODO remove before deploy
RealmInstace = Realm.getInstance(config)
Timber.i("Realm file path: ", RealmInstace?.path)
val action = intent?.action
when (action) {
ACTION_UPDATE_GFTS -> updateGfts()
ACTION_UPDATE_GFTS_REALTIME -> updateGftsReal() // this is called
REALM_GET_ALL_TRAIN_MAP -> getTrainMapData(intent)
}
exportDatabase()
// RealmInstace?.close()
RealmInstace = null
}
private fun updateGftsReal() {
var file:File?=null
AsyncDownloader(this, null, { f ->
file = f
if(file!=null && file!!.exists())
GftsRealRealmParser(applicationContext, file!!, RealmInstace!!)
else
Timber.e("Failed to download trip updates", GFTS_REALTIME_TRIP_URL)
}).execute(URL(GFTS_REALTIME_TRIP_URL)).get(2, TimeUnit.MINUTES)
}
class GftsRealRealmParser(val context: Context, val file: File, val realm: Realm) {
init {
var feedr: FeedMessageR? = null
var inputStream = BufferedInputStream(FileInputStream(file))
try {
val url = URL("http://developer.mbta.com/lib/GTRTFS/Alerts/TripUpdates.pb")
val feed = GtfsRealtime.FeedMessage.parseDelimitedFrom(url.openStream())
feedr = FeedMessageR(feed)
realm.executeTransaction {
Timber.i("Committing ${feedr!!.entityList.size} to the realtime db.")
realm?.copyToRealm(feedr)
// val train = realm.where(TripDescriptorR::class.java).contains("route_id", "31760754").findFirst()
}
} catch (e: IOException) {
Timber.e(e.message, e)
e.printStackTrace()
} catch(e: Exception) {
Timber.e(e.message, e)
e.printStackTrace()
}
if (feedr == null)
throw ParseException("Failed to parse file", 0)
}
}
EDIT 4 ----
see answer below
I found the solution. I was calling the wrong funtion. I was calling parseDelimitedFrom
where I should've been calling parseFrom
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With