
ch.viseon.openOrca.client.XMLHttpRequestTransmitter.kt Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2017 viseon gmbh
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ch.viseon.openOrca.client
import ch.viseon.openOrca.share.CommandData
import ch.viseon.openOrca.share.ExceptionWithCause
import ch.viseon.openOrca.share.Source
import ch.viseon.openOrca.share.StringCodec
import kodando.rxjs.Rx
import org.w3c.dom.events.Event
import org.w3c.xhr.XMLHttpRequest
interface Transmitter {
/**
* Returns the command that we get as a response from the server.
*/
fun sendCommands(commands: List): Rx.IObservable
}
class XMLHttpRequestTransmitter(val url: String, val codec: StringCodec) : Transmitter {
private class CommandSubjectPair(val commands: Iterable) {
val subject = Rx.Subject()
}
private val commandQueue: MutableList = mutableListOf()
private val request = XMLHttpRequest()
private var alreadySending = false
/**
* Returns the command that we get as a response from the server.
*/
override fun sendCommands(commands: List): Rx.IObservable {
if (commands.isEmpty()) {
return Rx.Observable.Companion.empty()
}
return Rx.Observable { observer ->
val pair = CommandSubjectPair(commands)
commandQueue.add(pair)
val result = pair.subject.subscribe({
observer.next(it)
}, { error ->
observer.error(error as Error)
}, {
observer.complete()
sendComplete()
})
send()
result
}
}
private fun send() {
if (alreadySending) {
return
}
if (commandQueue.isEmpty()) {
return
}
alreadySending = true
val pair = commandQueue.removeAt(0)
val handler = Handler(pair.subject, request, codec)
request.onreadystatechange = handler::readyStateHandler
request.onerror = handler::onErrorHandler
request.open("POST", url, true)
request.withCredentials = true
request.setRequestHeader("Content-Type", "${codec.mimeType}; charset=${codec.encoding}")
request.send(codec.encode(pair.commands))
}
private fun sendComplete() {
alreadySending = false
send()
}
}
private class Handler(val subject: Rx.Subject, val request: XMLHttpRequest, val codec: StringCodec) {
fun onErrorHandler(event: Event): Unit {
subject.error(Error("Error received: $event"))
}
fun readyStateHandler(event: Event): Unit {
if (request.readyState != XMLHttpRequest.DONE) {
return
}
if (request.status != 200.toShort()) {
subject.error(Error("Incorrect status received '${request.status}', expected 200."))
return
}
val responseText = request.responseText.trim()
try {
val responseCommands = this.codec.decode(Source.RESPONSE, responseText)
onDone(responseCommands)
} catch (exception: ExceptionWithCause) {
val newError = ExceptionWithCause("Error occurred parsing responseText: '$responseText'", exception)
console.error(newError)
subject.error(Error(newError.toString()))
}
}
private fun onDone(commands: Iterable) {
commands.forEach { subject.next(it) }
subject.complete()
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy