All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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