Commit 36a38e75 authored by 140bpmdubstep's avatar 140bpmdubstep 📻
Browse files

Loading commit information from gitlab jobs

parent 246febf9
#Project files
/.idea
/.vscode
/.metals
.bloop/
metals.sbt
# Build files
target/
/*.jar
# Proxy configuration
cacerts
# Temp files
/*.log
/*.so
/*.dll
/save/
/ref/
/node_modules/
#Project files
/.idea
/.vscode
/.metals
.bloop/
metals.sbt
# Build files
target/
/*.jar
# Proxy configuration
cacerts
# Temp files
/*.log
/*.so
/*.dll
/save/
/ref/
/node_modules/
## 0.3.11
* Fix: allow real numbers in mouse wheel event delta
## 0.3.10
* Security fix: official patch for the "too long without yielding" issue
## 0.3.9
* Fix: `computer.getDeviceInfo()`
## 0.3.8
* Updated to 0.4.0 version of ocelot-brain (workspaces & persistence)
## 0.3.7
* Security patch (resource exhaustion mitigation)
## 0.3.6
* Updated to 0.3.1 version of ocelot-brain (OC upgraded to 1.7.4)
## 0.3.5
* Updated to 0.2.7 version of ocelot-brain (now hard drives are persisted)
## 0.3.4
* Added on more hard drive (this time in the unmanaged mode)
## 0.3.3
* Added randomly generated user names
* Reconfigured test instance to prohibit computer owning
* Added `computer.beep(frequency, duration)` support for client-side
## 0.3.2
* Refactored font rendering (again)
* Fixed: inverted scroll event
* Fixed: vertical gpu.set()
## 0.3.1
* Added active WS connections counter (people online)
* Fixed some rendering glitches in Firefox / Linux
## 0.3.0
* Finished pixel perfect rendering
* Added redstone card Tier 2
* Renamed OpenOS floppy
* Added `hpm` to default OpenOS image
* Fixed copy-pasting
## 0.2.2
* Experimental rendering changes
* Experimental support for clipboard pasting with `Ctrl + V`
* Experimental support for mobile phones
* Added character codes for `Enter`, `Tab`, `Backspace` and `Ctrl + C`
* Fix: release all pressed keys when the page loses focus
## 0.2.1
* Added changelog
* Changed default Lua BIOS to advancedLoader (thanks Luca_S)
## 0.2.0
* Fixed render bugs
* Improved CSS styles
* Added `turn on` and `turn off` buttons
* Added support for resolution changes
* Mouse events support
* Added one more memory plank Tier 3.5
* Added HDD Tier 3
* New redstone card component (thanks Laine)
* Footer with [ocelot.online] version
## 0.1.0
* Basic version.
One workspace with Tier 4 computer case, Tier 3 CPU, one memory plank Tier 3.5,
internet card, graphics card Tier 3 and screen Tier 2. OpenOS Lua BIOS and OpenOS
## 0.4.0
* Added: [Ocelot Desktop](https://gitlab.com/cc-ru/ocelot/ocelot-desktop) frontpage
## 0.3.11
* Fix: allow real numbers in mouse wheel event delta
## 0.3.10
* Security fix: official patch for the "too long without yielding" issue
## 0.3.9
* Fix: `computer.getDeviceInfo()`
## 0.3.8
* Updated to 0.4.0 version of ocelot-brain (workspaces & persistence)
## 0.3.7
* Security patch (resource exhaustion mitigation)
## 0.3.6
* Updated to 0.3.1 version of ocelot-brain (OC upgraded to 1.7.4)
## 0.3.5
* Updated to 0.2.7 version of ocelot-brain (now hard drives are persisted)
## 0.3.4
* Added on more hard drive (this time in the unmanaged mode)
## 0.3.3
* Added randomly generated user names
* Reconfigured test instance to prohibit computer owning
* Added `computer.beep(frequency, duration)` support for client-side
## 0.3.2
* Refactored font rendering (again)
* Fixed: inverted scroll event
* Fixed: vertical gpu.set()
## 0.3.1
* Added active WS connections counter (people online)
* Fixed some rendering glitches in Firefox / Linux
## 0.3.0
* Finished pixel perfect rendering
* Added redstone card Tier 2
* Renamed OpenOS floppy
* Added `hpm` to default OpenOS image
* Fixed copy-pasting
## 0.2.2
* Experimental rendering changes
* Experimental support for clipboard pasting with `Ctrl + V`
* Experimental support for mobile phones
* Added character codes for `Enter`, `Tab`, `Backspace` and `Ctrl + C`
* Fix: release all pressed keys when the page loses focus
## 0.2.1
* Added changelog
* Changed default Lua BIOS to advancedLoader (thanks Luca_S)
## 0.2.0
* Fixed render bugs
* Improved CSS styles
* Added `turn on` and `turn off` buttons
* Added support for resolution changes
* Mouse events support
* Added one more memory plank Tier 3.5
* Added HDD Tier 3
* New redstone card component (thanks Laine)
* Footer with [ocelot.online] version
## 0.1.0
* Basic version.
One workspace with Tier 4 computer case, Tier 3 CPU, one memory plank Tier 3.5,
internet card, graphics card Tier 3 and screen Tier 2. OpenOS Lua BIOS and OpenOS
floppy included.
\ No newline at end of file
## ocelot-online
OpenComputers emulator in form of a web-application.
Uses `ocelot-brain` module to do all the emulation work under the hood.
### demo
Demo build can be tested here: [https://ocelot.fomalhaut.me/](https://ocelot.fomalhaut.me/)
It consists of a single shared computer instance
with the following configuration:
* Creative computer case
* CPU (Tier 3)
* Graphics card (Tier 3)
* 2x Memory planks (Tier 3.5)
* HDD, managed (Tier 3)
* HDD, unmanaged (Tier 3)
* Internet card
* Redstone card (Tier 2)
* Disk drive with OpenOS installation floppy inserted
* EEPROM with advanced OS loader
* Screen (Tier 2)
* Keyboard
### build instructions
* Import the project into your favorite IDE with the last Scala and SBT installed
* Put a compiled `ocelot-brain` JAR file into `lib/` directory (create it if necessary)
* Run `sbt assembly` task to package the project to a JAR file with dependencies
* Take the JAR file from `target/scala-x.xx/` folder
* Run it using `java -jar ocelot-online-x.x.x.jar` command
The working directory of ocelot.online instance must contain the `static/`
folder from this repo and the configured `ocelot.conf` file.
Also, you can put there a `brain.conf` file to configure the emulator core.
This config file is just a copy of OpenComputers configuration.
**P.S.** This project is a *work-in-progress*, breaking changes and bugs will break
things from time to time. Beware.
## ocelot-online
OpenComputers emulator in form of a web-application.
Uses `ocelot-brain` module to do all the emulation work under the hood.
### demo
Demo build can be tested here: [https://ocelot.fomalhaut.me/](https://ocelot.fomalhaut.me/)
It consists of a single shared computer instance
with the following configuration:
* Creative computer case
* CPU (Tier 3)
* Graphics card (Tier 3)
* 2x Memory planks (Tier 3.5)
* HDD, managed (Tier 3)
* HDD, unmanaged (Tier 3)
* Internet card
* Redstone card (Tier 2)
* Disk drive with OpenOS installation floppy inserted
* EEPROM with advanced OS loader
* Screen (Tier 2)
* Keyboard
### build instructions
* Import the project into your favorite IDE with the last Scala and SBT installed
* Put a compiled `ocelot-brain` JAR file into `lib/` directory (create it if necessary)
* Run `sbt assembly` task to package the project to a JAR file with dependencies
* Take the JAR file from `target/scala-x.xx/` folder
* Run it using `java -jar ocelot-online-x.x.x.jar` command
The working directory of ocelot.online instance must contain the `static/`
folder from this repo and the configured `ocelot.conf` file.
Also, you can put there a `brain.conf` file to configure the emulator core.
This config file is just a copy of OpenComputers configuration.
**P.S.** This project is a *work-in-progress*, breaking changes and bugs will break
things from time to time. Beware.
name := "ocelot-online"
// do not forget to change version in Ocelot.scala
version := "0.3.11"
scalaVersion := "2.13.1"
lazy val root = project.in(file("."))
.dependsOn(brain % "compile->compile")
.aggregate(brain)
lazy val brain = ProjectRef(file("lib/ocelot-brain"), "ocelot-brain")
libraryDependencies ++= Seq(
"com.typesafe.akka" %% "akka-http" % "10.1.11",
"com.typesafe.akka" %% "akka-stream" % "2.6.3",
"com.typesafe" % "config" % "1.4.0",
"org.scalatra.scalate" %% "scalate-core" % "1.9.8"
)
assemblyJarName := s"ocelot-online-${version.value}.jar"
assemblyMergeStrategy in assembly := {
case PathList("META-INF", "MANIFEST.MF") => MergeStrategy.discard
case "reference.conf" => MergeStrategy.concat
case _ => MergeStrategy.first
}
name := "ocelot-online"
// do not forget to change version in Ocelot.scala
version := "0.4.0"
scalaVersion := "2.13.1"
lazy val root = project.in(file("."))
.dependsOn(brain % "compile->compile")
.aggregate(brain)
lazy val brain = ProjectRef(file("lib/ocelot-brain"), "ocelot-brain")
libraryDependencies ++= Seq(
"com.typesafe.akka" %% "akka-http" % "10.1.11",
"com.typesafe.akka" %% "akka-stream" % "2.6.3",
"com.typesafe" % "config" % "1.4.0",
"org.scalatra.scalate" %% "scalate-core" % "1.9.8",
"io.spray" %% "spray-json" % "1.3.6"
)
assemblyJarName := s"ocelot-online-${version.value}.jar"
assemblyMergeStrategy in assembly := {
case PathList("META-INF", "MANIFEST.MF") => MergeStrategy.discard
case "reference.conf" => MergeStrategy.concat
case _ => MergeStrategy.first
}
# Server configuration
# Will be used by backend akka-http webserver
server {
host: "0.0.0.0"
port: 1097
blacklist: []
}
# Client configuration
# Will be used by frontend websockets client
client {
host: "ws://localhost:1097"
}
# Server configuration
# Will be used by backend akka-http webserver
server {
host: "0.0.0.0"
port: 1097
blacklist: []
gitlab_token: ""
}
# Client configuration
# Will be used by frontend websockets client
client {
host: "ws://localhost:1097"
}
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.7")
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.7")
# suppress inspection "UnusedProperty" for whole file
sbt.version = 1.3.8
# suppress inspection "UnusedProperty" for whole file
sbt.version = 1.3.8
package totoro.ocelot.online
import spray.json.DefaultJsonProtocol
import spray.json.DefaultJsonProtocol.{StringJsonFormat, jsonFormat1, jsonFormat5, listFormat}
case class GitlabJob(commit: Commit)
case class Commit(id: String, web_url: String, authored_date: String, author_name: String, short_id: String)
object GitlabJob extends DefaultJsonProtocol {
implicit val commitFormat = jsonFormat5(Commit)
implicit val gitlabJobFormat = jsonFormat1(GitlabJob.apply)
}
\ No newline at end of file
package totoro.ocelot.online
import java.io.File
import java.net.InetSocketAddress
import java.time.LocalDate
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.model.{ContentType, ContentTypes, HttpEntity, HttpHeader, HttpResponse, MediaTypes, StatusCode, StatusCodes}
import akka.http.scaladsl.model.ws.{BinaryMessage, Message, TextMessage}
import akka.http.scaladsl.server.Directives._
import akka.stream.scaladsl.{BroadcastHub, Flow, Keep, Sink, Source}
import akka.stream.{ActorMaterializer, OverflowStrategy}
import org.apache.logging.log4j.{LogManager, Logger}
import org.fusesource.scalate.{RenderContext, Template, TemplateEngine}
import totoro.ocelot.brain.user.User
import scala.concurrent.ExecutionContextExecutor
import scala.io.StdIn
import scala.util.{Failure, Success}
object Ocelot {
private val Name = "ocelot.online"
// do not forget to change version in build.sbt
private val Version = "0.3.11"
var logger: Option[Logger] = None
def log: Logger = logger.getOrElse(LogManager.getLogger(Name))
def main(args: Array[String]): Unit = {
// init
implicit val system: ActorSystem = ActorSystem("ocelot-system")
implicit val materializer: ActorMaterializer = ActorMaterializer()
// needed for the future flatMap/onComplete in the end
implicit val executionContext: ExecutionContextExecutor = system.dispatcher
val templateSource = new File("template/index.mustache").getCanonicalPath
val template = new TemplateEngine()
Settings.load(new File("ocelot.conf"))
// demo source
val queue = Source.queue[TextMessage](256, OverflowStrategy.dropHead)
val (mat, source) = queue.toMat(BroadcastHub.sink(bufferSize = 256))(Keep.both).run()
source.runWith(Sink.ignore)
// init demo workspace
val workspace = new Workspace()
workspace.init()
workspace.subscribe(mat)
workspace.turnOn()
def run(): Unit = {
new Thread(() => {
while (workspace.isRunning) {
workspace.update()
Thread.sleep(50)
}
log.debug("Main thread closed...")
}).start()
log.debug("Created new main thread.")
}
run()
// create websockets handler
var online = 0
def watchDisconnectsFlow[T]: Flow[T, T, Any] = Flow[T]
.watchTermination()((_, f) => {
online += 1
mat offer TextMessage(s"online\n$online")
f.onComplete { result =>
online -= 1
mat offer TextMessage(s"online\n$online")
result match {
case Failure(cause) =>
log.error(s"WS stream failed!", cause)
case _ => // ignore normal termination
}
}
})
def wsHandler(user: User): Flow[Message, Message, Any] = Flow[Message]
.mapConcat {
case tm: TextMessage =>
tm.textStream.runFold("")(_ + _).onComplete {
case Success(message) =>
val parts = message.split(" ")
parts.head match {
case "keydown" => workspace.keyDown(parts(1).toInt.toChar, parts(2).toInt, user)
case "keyup" => workspace.keyUp(parts(1).toInt.toChar, parts(2).toInt, user)
case "keyup-all" => workspace.releasePressedKeys(user)
case "clipboard" => workspace.clipboard(message.drop(10), user)
case "mousedown" => workspace.mouseDown(parts(1).toInt, parts(2).toInt, parts(3).toInt, user)
case "mouseup" => workspace.mouseUp(parts(1).toInt, parts(2).toInt, parts(3).toInt, user)
case "mousedrag" => workspace.mouseDrag(parts(1).toInt, parts(2).toInt, parts(3).toInt, user)
case "mousewheel" => workspace.mouseScroll(parts(1).toInt, parts(2).toInt, parts(3).toFloat.toInt, user)
case "state" => workspace.sendState()
case "turnon" =>
if (!workspace.isRunning) {
workspace.turnOn()
run()
mat offer TextMessage("turnon-success")
} else {
mat offer TextMessage("turnon-failure")
}
case "turnoff" =>
if (workspace.isRunning) {
workspace.turnOff()
mat offer TextMessage("turnoff-success")
} else {
mat offer TextMessage("turnoff-failure")
}
case "online" =>
mat offer TextMessage(s"online\n$online")
case _ => // pass
}
case _ =>
}
Nil
case bm: BinaryMessage =>
// ignore binary messages but drain content to avoid the stream being clogged
bm.dataStream.runWith(Sink.ignore)
Nil
}
.merge(source)
.via(watchDisconnectsFlow)
// define routes
def route(address: InetSocketAddress) =
path("stream") {
ignoreTrailingSlash {
optionalHeaderValueByName("X-Real-Ip") { realIp =>
val nickname = NameGen.name((address.toString + LocalDate.now.toString).hashCode)
val ip = realIp match {
case Some(ip) => ip
case None => "NGINX proxy not configured"
}
val maskedIp = address.toString
val banned = Settings.get.blacklist.exists(value => ip.contains(value) || maskedIp.contains(value))
log.info(s"User connected: $nickname ($maskedIp / ${address.getAddress.getCanonicalHostName} / $ip${if (banned) " / banned" else ""})")
if (!banned) handleWebSocketMessages(wsHandler(User(nickname))) else complete(HttpResponse(StatusCodes.PaymentRequired))
}
}
} ~
path("config.js") {
get {
complete(s"var version = '$Version'; var host = '${Settings.get.clientHost}';")
}
} ~
ignoreTrailingSlash {
path("desktop") {
get {
val model = Map(
"last_update" -> "2022-01-12",
"updated_by" -> "Fingercomp",
"commit_url" -> "https://google.com",
"commit" -> "412382389-4rwe9fu8adsfsadfasa"
)
val entity = HttpEntity(ContentTypes.`text/html(UTF-8)`, template.layout(templateSource, model))
complete(entity);
}
}
} ~
pathEndOrSingleSlash {
getFromFile("static/index.html")
} ~
getFromDirectory("static")
// run
val bindingFuture = Http()
.bind(Settings.get.serverHost, Settings.get.serverPort)
.runWith(Sink foreach { conn =>
val address = conn.remoteAddress
conn.handleWith(route(address))
})
log.info(s"Server online at http://${Settings.get.serverHost}:${Settings.get.serverPort}/\nPress Enter to stop...")
StdIn.readLine()
bindingFuture
.onComplete(_ => system.terminate())
workspace.turnOff()
}
}
package totoro.ocelot.online
import java.io.File
import java.net.InetSocketAddress
import java.time.{LocalDate, LocalDateTime}
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.model.{ContentTypes, HttpEntity, HttpRequest, HttpResponse, StatusCodes, headers}
import akka.http.scaladsl.model.ws.{BinaryMessage, Message, TextMessage}
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.unmarshalling.Unmarshal
import akka.stream.scaladsl.{BroadcastHub, Flow, Keep, Sink, Source}
import akka.stream.{ActorMaterializer, OverflowStrategy}
import org.apache.logging.log4j.{LogManager, Logger}
import org.fusesource.scalate.TemplateEngine
import spray.json._
import DefaultJsonProtocol._
import totoro.ocelot.brain.user.User
import scala.concurrent.{ExecutionContextExecutor, Future}
import scala.io.StdIn
import scala.language.postfixOps
import scala.util.{Failure, Success}
import java.time.format.DateTimeFormatter
object Ocelot {
private val Name = "ocelot.online"
// do not forget to change version in build.sbt
private val Version = "0.4.0"
private val OcelotProjId = 9941848
var logger: Option[Logger] = None
def log: Logger = logger.getOrElse(LogManager.getLogger(Name))
def main(args: Array[String]): Unit = {
// init
implicit val system: ActorSystem = ActorSystem("ocelot-system")
implicit val materializer: ActorMaterializer = ActorMaterializer()
// needed for the future flatMap/onComplete in the end
implicit val executionContext: ExecutionContextExecutor = system.dispatcher
val templateSource = new File("template/index.mustache").getCanonicalPath
val template = new TemplateEngine()
val formatterOutput = DateTimeFormatter.ofPattern("yyyy-MM-dd")
val formaterInput = DateTimeFormatter.ISO_OFFSET_DATE_TIME
Settings.load(new File("ocelot.conf"))
// demo source
val queue = Source.queue[TextMessage](256, OverflowStrategy.dropHead)