Skip to content

Commit

Permalink
Initial server setup
Browse files Browse the repository at this point in the history
  • Loading branch information
jessehartloff committed Apr 20, 2020
1 parent cf0d6a9 commit a5164db
Show file tree
Hide file tree
Showing 11 changed files with 405 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
*.class
*.log
.idea/
47 changes: 47 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
FROM ubuntu:18.04

RUN apt-get update

RUN apt-get install -y wget

#Java Setup
RUN apt-get update --fix-missing
RUN apt-get install -y default-jdk

#Scala setup
RUN apt-get remove scala-library scala
RUN wget http://scala-lang.org/files/archive/scala-2.12.6.deb
RUN dpkg -i scala-2.12.6.deb
RUN apt-get update
RUN apt-get install -y scala

RUN apt-get install -y gnupg2
RUN echo "deb https://dl.bintray.com/sbt/debian /" | tee -a /etc/apt/sources.list.d/sbt.list
RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 2EE0EA64E40A89B84B2DF73499E82A75642AC823
RUN apt-get update
RUN apt-get install -y sbt

#Maven Setup
RUN apt-get install -y maven


# Set the home directory to /root and cd into that directory
ENV HOME /root
WORKDIR /root


# Copy all app files into the image
COPY . .

# Download dependancies and build the app
RUN mvn package


# Allow port 8080 to be accessed from outside the container
EXPOSE 8080

ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.2.1/wait /wait
RUN chmod +x /wait

# Run the app
CMD /wait && java -jar target/office-hours-0.0.1-jar-with-dependencies.jar
19 changes: 19 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
version: '3.3'
services:
nginx:
build: ./nginx
ports:
- '9005:80'
mysql:
image: mysql
environment:
MYSQL_ROOT_PASSWORD: 'changeme'
MYSQL_DATABASE: 'officehours'
MYSQL_USER: 'sqluser'
MYSQL_PASSWORD: 'changeme'
app:
build: .
environment:
WAIT_HOSTS: mysql:3306
DB_USERNAME: 'sqluser'
DB_PASSWORD: 'changeme'
6 changes: 6 additions & 0 deletions nginx/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
FROM nginx

COPY ./public /usr/share/nginx/html
COPY ./default.conf /etc/nginx/conf.d

EXPOSE 80
17 changes: 17 additions & 0 deletions nginx/default.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
server {
listen 80;
server_name localhost;

location / {
root /usr/share/nginx/html;
index index.html index.htm;
}

location /socket.io {
proxy_pass http://app:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}

}
29 changes: 29 additions & 0 deletions nginx/public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Office Hours</title>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"></script>
</head>
<body>

<br/>

<h3 id="message">Welcome!</h3>

<p>Name</p>
<input type="text" id="name"/>
<button onclick="enterQueue();">Enter Queue</button>
<br/><br/>

<button onclick="readyToHelp();">TA Ready to Help</button>

<br/>

<div id="queue"></div>

<script src="officeHours.js"></script>


</body>
</html>
28 changes: 28 additions & 0 deletions nginx/public/officeHours.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const socket = io.connect({transports: ['websocket']});

socket.on('queue', displayQueue);
socket.on('message', displayMessage);

function displayMessage(newMessage) {
document.getElementById("message").innerHTML = newMessage;
}

function displayQueue(queueJSON) {
const queue = JSON.parse(queueJSON);
let formattedQueue = "";
for (const student of queue) {
formattedQueue += student['username'] + " has been waiting since " + student['timestamp'] + "<br/>"
}
document.getElementById("queue").innerHTML = formattedQueue;
}


function enterQueue() {
let name = document.getElementById("name").value;
socket.emit("enter_queue", name);
document.getElementById("name").value = "";
}

function readyToHelp() {
socket.emit("ready_for_student");
}
88 changes: 88 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<project xmlns="http://maven.apache.org/POM/4.0.0">
<groupId>edu.buffalo.cse</groupId>
<artifactId>office-hours</artifactId>
<modelVersion>4.0.0</modelVersion>
<url>http://maven.apache.org</url>
<version>0.0.1</version>

<properties>
<encoding>UTF-8</encoding>
<scala.version>2.12.9</scala.version>
</properties>

<dependencies>

<!-- https://mvnrepository.com/artifact/com.typesafe.play/play-json -->
<dependency>
<groupId>com.typesafe.play</groupId>
<artifactId>play-json_2.12</artifactId>
<version>2.7.1</version>
</dependency>

<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.15</version>
</dependency>

<dependency>
<groupId>com.corundumstudio.socketio</groupId>
<artifactId>netty-socketio</artifactId>
<version>1.7.12</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-simple -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.28</version>
</dependency>

</dependencies>

<build>
<plugins>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>model.OfficeHoursServer</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>

<plugin>
<groupId>org.scala-tools</groupId>
<artifactId>maven-scala-plugin</artifactId>
<version>2.15.2</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>

</plugins>
</build>

</project>
55 changes: 55 additions & 0 deletions src/main/scala/model/Database.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package model

import java.sql.{Connection, DriverManager, ResultSet}

object Database {

val url = "jdbc:mysql://mysql/officehours"
val username: String = sys.env("DB_USERNAME")
val password: String = sys.env("DB_PASSWORD")

var connection: Connection = DriverManager.getConnection(url, username, password)
setupTable()


def setupTable(): Unit = {
val statement = connection.createStatement()
statement.execute("CREATE TABLE IF NOT EXISTS queue (username TEXT, timestamp BIGINT)")
}


def addStudentToQueue(student: StudentInQueue): Unit = {
val statement = connection.prepareStatement("INSERT INTO queue VALUE (?, ?)")

statement.setString(1, student.username)
statement.setLong(2, student.timestamp)

statement.execute()
}


def removeStudentFromQueue(username: String): Unit = {
val statement = connection.prepareStatement("DELETE FROM queue WHERE username=?")

statement.setString(1, username)

statement.execute()
}


def getQueue(): List[StudentInQueue] = {
val statement = connection.prepareStatement("SELECT * FROM queue")
val result: ResultSet = statement.executeQuery()

var queue: List[StudentInQueue] = List()

while (result.next()) {
val username = result.getString("username")
val timestamp = result.getLong("timestamp")
queue = new StudentInQueue(username, timestamp) :: queue
}

queue
}

}
79 changes: 79 additions & 0 deletions src/main/scala/model/OfficeHoursServer.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package model

import com.corundumstudio.socketio.listener.{DataListener, DisconnectListener}
import com.corundumstudio.socketio.{AckRequest, Configuration, SocketIOClient, SocketIOServer}
import play.api.libs.json.{JsValue, Json}


class OfficeHoursServer() {

var usernameToSocket: Map[String, SocketIOClient] = Map()
var socketToUsername: Map[SocketIOClient, String] = Map()

val config: Configuration = new Configuration {
setHostname("0.0.0.0")
setPort(8080)
}

val server: SocketIOServer = new SocketIOServer(config)

server.addDisconnectListener(new DisconnectionListener(this))
server.addEventListener("enter_queue", classOf[String], new EnterQueueListener(this))
server.addEventListener("ready_for_student", classOf[Nothing], new ReadyForStudentListener(this))

server.start()

def queueJSON(): String = {
val queue: List[StudentInQueue] = Database.getQueue()
val queueJSON: List[JsValue] = queue.map((entry: StudentInQueue) => entry.asJsValue())
Json.stringify(Json.toJson(queueJSON))
}

}

object OfficeHoursServer {
def main(args: Array[String]): Unit = {
new OfficeHoursServer()
}
}


class DisconnectionListener(server: OfficeHoursServer) extends DisconnectListener {
override def onDisconnect(socket: SocketIOClient): Unit = {
if (server.socketToUsername.contains(socket)) {
val username = server.socketToUsername(socket)
server.socketToUsername -= socket
if (server.usernameToSocket.contains(username)) {
server.usernameToSocket -= username
}
}
}
}


class EnterQueueListener(server: OfficeHoursServer) extends DataListener[String] {
override def onData(socket: SocketIOClient, username: String, ackRequest: AckRequest): Unit = {
Database.addStudentToQueue(StudentInQueue(username, System.nanoTime()))
server.socketToUsername += (socket -> username)
server.usernameToSocket += (username -> socket)
server.server.getBroadcastOperations.sendEvent("queue", server.queueJSON())
}
}


class ReadyForStudentListener(server: OfficeHoursServer) extends DataListener[Nothing] {
override def onData(socket: SocketIOClient, dirtyMessage: Nothing, ackRequest: AckRequest): Unit = {
val queue = Database.getQueue().sortBy(_.timestamp)
if(queue.nonEmpty){
val studentToHelp = queue.head
Database.removeStudentFromQueue(studentToHelp.username)
socket.sendEvent("message", "You are now helping " + studentToHelp.username)
if(server.usernameToSocket.contains(studentToHelp.username)){
server.usernameToSocket(studentToHelp.username).sendEvent("message", "A TA is ready to help you")
}
server.server.getBroadcastOperations.sendEvent("queue", server.queueJSON())
}
}
}


Loading

0 comments on commit a5164db

Please sign in to comment.