
ilcali.capture-server_2.8.1.0.0.2.source-code.ImageStream.scala Maven / Gradle / Ivy
The newest version!
package capture
package server
import unfiltered.request._
import unfiltered.response._
import unfiltered.netty._
import org.jboss.netty.handler.codec.http.{
HttpHeaders,
DefaultHttpChunk,
DefaultHttpChunkTrailer
}
import org.jboss.netty.channel.group.{
DefaultChannelGroup,
ChannelGroupFuture
}
import org.jboss.netty.channel.{
Channel,
ChannelFuture,
ChannelFutureListener
}
import org.jboss.netty.buffer.ChannelBuffers
import capture.control.{
Robot,
ForeverRunning
}
case class ImageProps(scaleX: Double, scaleY: Double, qual: Float, p: Boolean)
// Code greatly inspired by n8han/shouty
// https://github.com/n8han/shouty/blob/master/src/main/scala/stream.scala
case class ImageStream(delay: Long) extends Interface with ForeverRunning {
@volatile private var settings = ImageProps(1.0, 1.0, 0.2f, true)
val boundary = "desktrotopio"
val MixedReplace =
Ok ~>
unfiltered.response.Connection(HttpHeaders.Values.CLOSE) ~>
ContentType("multipart/x-mixed-replace; boundary=--%s".format(boundary))
val interface =
Ok ~>
ContentType("text/javascript") ~>
ResponseString("")
val listeners = new DefaultChannelGroup("Image Streams")
def enableControl = false
override def responder = super.responder orElse {
case img: ImageProps => settings = img
}
def preload = {
// Imagine this file will actually be different
// For now we'll just blank it out
case req @ Path(Seg("interface.js" :: Nil)) => req.respond(interface)
case req @ Path(Seg("image" :: DesktopImage(x, y, q, p) :: Nil)) =>
// TODO: What about the controller changing service settings?
val initial = req.underlying.defaultResponse(MixedReplace)
val ch = req.underlying.event.getChannel
val future = ch.write(initial)
future.addListener(() => listeners.add(ch))
future.addListener(ChannelFutureListener.CLOSE_ON_FAILURE)
}
def handleIndex(index: Long) {
if (!listeners.isEmpty) {
val ImageProps(x, y, q, p) = settings
val shot = if (p) Robot.screenshot.withPointer else Robot.screenshot
val data = if (x == 1.0 && x == y)
shot.data(q) else shot.scale(x, y).data(q)
write(data)
}
}
// Write complete boundary jpeg data
def write(data: Array[Byte]) {
val border = "\n\n--%s\nContent-Type: image/jpeg\nContent-Length: %d\n\n".format(
boundary, data.length
).getBytes
val together = border ++ data
listeners.write(new DefaultHttpChunk(
ChannelBuffers.copiedBuffer(together, 0, together.length)
))
}
implicit def block2listener[T](block: () => T): ChannelFutureListener = {
new ChannelFutureListener {
def operationComplete(future: ChannelFuture) { block() }
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy