Skip to content
Permalink
Browse files

Created BackgroundUpdates to support non-UI updating

Added support to resume connections on the server
  • Loading branch information
darkfrog26 committed Nov 15, 2019
1 parent be6839f commit 7becc1ed792d0f1792c08c4065b80721f48688d0
@@ -1,6 +1,6 @@
package io.youi.app

import io.youi.{AnimationFrame, History}
import io.youi.{BackgroundUpdates, History}
import io.youi.client.{BlobData, WebSocketClient}
import io.youi.communication.Connection
import io.youi.http.ConnectionStatus
@@ -58,6 +58,8 @@ trait ClientConnectedApplication[C <: Connection] extends ClientApplication with
ws.connect()
}

def reconnected(): Future[Unit] = Future.successful(())

def upload(file: File): Future[String] = {
val webSocket = connection.webSocket().getOrElse(throw new RuntimeException("Not connected!"))
val fileName = file.name
@@ -76,10 +78,10 @@ trait ClientConnectedApplication[C <: Connection] extends ClientApplication with
upload.future
}

AnimationFrame.delta.attach { d =>
BackgroundUpdates.delta.attach { d =>
if (d >= 60.0) {
scribe.info(s"RESUME FROM SLEEP! Delta: $d, reconnecting...")
disconnected()
connection.disconnect()
}
}

@@ -98,7 +100,10 @@ trait ClientConnectedApplication[C <: Connection] extends ClientApplication with
case _ => // Ignore others
}
}
case ReconnectStrategy.Reconnect => Time.delay(reconnectDelay).flatMap(_ => connect()).map(_ => ())
case ReconnectStrategy.Reconnect => Time
.delay(reconnectDelay)
.flatMap(_ => connect())
.flatMap(_ => reconnected())
case ReconnectStrategy.Stop => ()
}

@@ -34,15 +34,11 @@ class ConnectionManager[C <: Connection](app: ServerConnectedApplication[C]) {
}

private def addConnection(listener: WebSocketListener): Unit = synchronized {
val connection = app.createConnection()
val connection = app.getOrCreateConnection(listener)
connection.webSocket := Some(listener)
_connections @= connection :: _connections()
_connections @= (connection :: _connections()).distinct
}

// TODO: Every thirty seconds unless killed by app.dispose
// TODO: Ping / Pong - Shouldn't it be the client, not the server?
// TODO: Timeout long-closed connections

private def removeConnection(connection: C): Unit = synchronized {
_connections @= _connections.filterNot(_ eq connection)
connection.disconnect()
@@ -1,11 +1,12 @@
package io.youi.app

import io.youi.communication.Connection
import io.youi.server.WebSocketListener

import scala.concurrent.duration._

trait ServerConnectedApplication[C <: Connection] extends ServerApplication with YouIConnectedApplication[C] {
def createConnection(): C
def getOrCreateConnection(listener: WebSocketListener): C
def connectionTimeout: FiniteDuration = 90.seconds

val connectionManager: ConnectionManager[C] = new ConnectionManager[C](this)
@@ -4,6 +4,7 @@ import io.youi.app._
import io.youi.http._
import io.youi.http.content.Content
import io.youi.net._
import io.youi.server.WebSocketListener
import io.youi.server.handler.{CachingManager, LanguageSupport}
import io.youi.server.dsl._
import profig.JsonUtil
@@ -16,7 +17,7 @@ object ServerExampleApplication extends ExampleApplication with ServerConnectedA

case class Greeting(message: String, name: String)

override def createConnection(): ExampleConnection = new ServerConnection
override def getOrCreateConnection(listener: WebSocketListener): ExampleConnection = new ServerConnection

override protected def init(): Future[Unit] = {
super.init().map { _ =>
@@ -1,28 +1,7 @@
package io.youi

import io.youi.task.TaskSupport
import org.scalajs.dom._
import reactify._

object AnimationFrame extends TaskSupport {
private var lastUpdate: Double = 0.0

val timeStamp: Val[Double] = Var(0.0)

private val updateFunction: Double => Unit = (highResTimeStamp: Double) => {
val delta = if (lastUpdate == 0.0) {
0.0
} else {
(highResTimeStamp - lastUpdate) / 1000.0
}
try {
timeStamp.asInstanceOf[Var[Double]] @= highResTimeStamp
update(delta)
} finally {
lastUpdate = highResTimeStamp
window.requestAnimationFrame(updateFunction)
}
}

window.requestAnimationFrame(updateFunction)
object AnimationFrame extends UpdateSupport {
override protected def run(): Unit = window.requestAnimationFrame(updateFunction)
}
@@ -0,0 +1,7 @@
package io.youi

import org.scalajs.dom.window

object BackgroundUpdates extends UpdateSupport {
override protected def run(): Unit = window.setTimeout(() => updateFunction(System.currentTimeMillis()), 100)
}
@@ -0,0 +1,29 @@
package io.youi

import io.youi.task.TaskSupport
import reactify.{Val, Var}

trait UpdateSupport extends TaskSupport {
private var lastUpdate: Double = 0.0

val timeStamp: Val[Double] = Var(0.0)

protected val updateFunction: Double => Unit = (highResTimeStamp: Double) => {
val delta = if (lastUpdate == 0.0) {
0.0
} else {
(highResTimeStamp - lastUpdate) / 1000.0
}
try {
this.timeStamp.asInstanceOf[Var[Double]] @= highResTimeStamp
update(delta)
} finally {
lastUpdate = highResTimeStamp
run()
}
}

run()

protected def run(): Unit
}
@@ -2,7 +2,7 @@ package io.youi.util

import java.util.concurrent.atomic.AtomicBoolean

import io.youi.AnimationFrame
import io.youi.BackgroundUpdates
import reactify.Var

import scala.concurrent.ExecutionContext.Implicits.global
@@ -19,7 +19,7 @@ class LazyFuture[T](f: () => Future[T], maxFrequency: FiniteDuration, automatic:
if (isReady) {
update()
} else {
AnimationFrame.once(delay.millis)(update())
BackgroundUpdates.once(delay.millis)(update())
}
}
}

0 comments on commit 7becc1e

Please sign in to comment.
You can’t perform that action at this time.