Merge pull request #15288 from antobinary/cleanup2
chore: cleanup of vertx-akka
This commit is contained in:
commit
b7e1cc3a54
53
labs/vertx-akka/.gitignore
vendored
53
labs/vertx-akka/.gitignore
vendored
@ -1,53 +0,0 @@
|
||||
.metadata
|
||||
.project
|
||||
.classpath
|
||||
.settings
|
||||
.history
|
||||
.worksheet
|
||||
gen
|
||||
**/*.swp
|
||||
**/*~.nib
|
||||
**/build/
|
||||
**/*.pbxuser
|
||||
**/*.perspective
|
||||
**/*.perspectivev3
|
||||
*.xcworkspace
|
||||
*.xcuserdatad
|
||||
*.iml
|
||||
project/*.ipr
|
||||
project/*.iml
|
||||
project/*.iws
|
||||
project/out
|
||||
project/*/target
|
||||
project/target
|
||||
project/*/bin
|
||||
project/*/build
|
||||
project/*.iml
|
||||
project/*/*.iml
|
||||
project/.idea
|
||||
project/.idea/*
|
||||
.idea/
|
||||
.DS_Store
|
||||
project/.DS_Store
|
||||
project/*/.DS_Store
|
||||
tm.out
|
||||
tmlog*.log
|
||||
*.tm*.epoch
|
||||
out/
|
||||
provisioning/.vagrant
|
||||
provisioning/*/.vagrant
|
||||
provisioning/*/*.known
|
||||
/sbt/akka-patterns-store/
|
||||
/daemon/src/build/
|
||||
*.lock
|
||||
logs/
|
||||
tmp/
|
||||
build/
|
||||
akka-patterns-store/
|
||||
lib_managed/
|
||||
.cache
|
||||
bin/
|
||||
.vertx/
|
||||
target/
|
||||
src/main/resources/
|
||||
|
@ -1,31 +0,0 @@
|
||||
#alignArguments=false
|
||||
alignParameters=true
|
||||
alignSingleLineCaseStatements=true
|
||||
#alignSingleLineCaseStatements.maxArrowIndent=40
|
||||
#allowParamGroupsOnNewlines=false
|
||||
#compactControlReadability=false
|
||||
#compactStringConcatenation=false
|
||||
danglingCloseParenthesis=Force
|
||||
#doubleIndentClassDeclaration=false
|
||||
doubleIndentConstructorArguments=true
|
||||
doubleIndentMethodDeclaration=true
|
||||
firstArgumentOnNewline=Force
|
||||
firstParameterOnNewline=Force
|
||||
#formatXml=true
|
||||
#indentLocalDefs=false
|
||||
#indentPackageBlocks=true
|
||||
#indentSpaces=2
|
||||
#indentWithTabs=false
|
||||
#multilineScaladocCommentsStartOnFirstLine=false
|
||||
#newlineAtEndOfFile=false
|
||||
#placeScaladocAsterisksBeneathSecondAsterisk=false
|
||||
#preserveSpaceBeforeArguments=false
|
||||
#rewriteArrowSymbols=false
|
||||
singleCasePatternOnNewline=false
|
||||
#spaceBeforeColon=false
|
||||
#spaceBeforeContextColon=false
|
||||
#spaceInsideBrackets=false
|
||||
#spaceInsideParentheses=false
|
||||
#spacesAroundMultiImports=true
|
||||
#spacesWithinPatternBinders=true
|
||||
|
@ -1,75 +0,0 @@
|
||||
import org.bigbluebutton.build._
|
||||
|
||||
import NativePackagerHelper._
|
||||
import com.typesafe.sbt.SbtNativePackager.autoImport._
|
||||
|
||||
enablePlugins(JavaServerAppPackaging)
|
||||
enablePlugins(UniversalPlugin)
|
||||
enablePlugins(DebianPlugin)
|
||||
|
||||
val compileSettings = Seq(
|
||||
organization := "org.bigbluebutton",
|
||||
|
||||
scalacOptions ++= List(
|
||||
"-unchecked",
|
||||
"-deprecation",
|
||||
"-Xlint",
|
||||
"-Ywarn-dead-code",
|
||||
"-language:_",
|
||||
"-target:jvm-1.8",
|
||||
"-encoding", "UTF-8"
|
||||
),
|
||||
javacOptions ++= List(
|
||||
"-Xlint:unchecked",
|
||||
"-Xlint:deprecation"
|
||||
)
|
||||
)
|
||||
|
||||
publishTo := Some(Resolver.file("file", new File(Path.userHome.absolutePath + "/dev/repo/maven-repo/releases")))
|
||||
|
||||
// We want to have our jar files in lib_managed dir.
|
||||
// This way we'll have the right path when we import
|
||||
// into eclipse.
|
||||
retrieveManaged := true
|
||||
|
||||
testOptions in Test += Tests.Argument(TestFrameworks.Specs2, "html", "console", "junitxml")
|
||||
|
||||
testOptions in Test += Tests.Argument(TestFrameworks.ScalaTest, "-h", "target/scalatest-reports")
|
||||
|
||||
Seq(Revolver.settings: _*)
|
||||
lazy val bbbVertxAkka = (project in file(".")).settings(name := "bbb-vertx-akka", libraryDependencies ++= Dependencies.runtime).settings(compileSettings)
|
||||
|
||||
// See https://github.com/scala-ide/scalariform
|
||||
// Config file is in ./.scalariform.conf
|
||||
scalariformAutoformat := true
|
||||
|
||||
//-----------
|
||||
// Packaging
|
||||
//
|
||||
// Reference:
|
||||
// https://github.com/muuki88/sbt-native-packager-examples/tree/master/akka-server-app
|
||||
// http://www.scala-sbt.org/sbt-native-packager/index.html
|
||||
//-----------
|
||||
mainClass := Some("org.bigbluebutton.Boot")
|
||||
|
||||
maintainer in Linux := "Richard Alam <ritzalam@gmail.com>"
|
||||
|
||||
packageSummary in Linux := "BigBlueButton Vertx Akka"
|
||||
|
||||
packageDescription := """BigBlueButton Core Vertx Akka."""
|
||||
|
||||
val user = "bigbluebutton"
|
||||
|
||||
val group = "bigbluebutton"
|
||||
|
||||
// user which will execute the application
|
||||
daemonUser in Linux := user
|
||||
|
||||
// group which will execute the application
|
||||
daemonGroup in Linux := group
|
||||
|
||||
javaOptions in Universal ++= Seq("-J-Xms130m", "-J-Xmx256m", "-Dconfig.file=conf/application.conf", "-Dlogback.configurationFile=conf/logback.xml")
|
||||
|
||||
debianPackageDependencies in Debian ++= Seq("java8-runtime-headless", "bash")
|
||||
|
||||
|
@ -1,44 +0,0 @@
|
||||
frontend ssl-in
|
||||
mode tcp
|
||||
log-format %ci:%cp\ [%t]\ %ft\ %b/%s\ %Tw/%Tc/%Tt\ %U:%B\ %ts\ %ac/%fc/%bc/%sc/%rc\ %hr\ %hs\ %sq/%bq
|
||||
|
||||
bind *:443,:::443 ssl crt /etc/ssl/ritz-ss.blindside-dev.com/ritz-ss.blindside-dev.com.pem
|
||||
|
||||
# Detect RTMP traffic
|
||||
# The first byte must be 0x03 (version 3)
|
||||
acl rtmp_handshake_ver req.payload(0,1) -m bin 03
|
||||
|
||||
# RTMP has a fixed-size handshake: 1 byte version + 1536 byte data.
|
||||
# This acl causes haproxy to not detect a request as rtmp unless
|
||||
# it's received at least that much data (and didn't match other things)
|
||||
#acl rtmp_handshake_size req.len ge 1537
|
||||
acl rtmp_handshake_size req.len ge 1
|
||||
|
||||
acl is_websocket path_beg -i /eventbus
|
||||
#acl is_websocket hdr(Upgrade) -i WebSocket
|
||||
|
||||
# haproxy has built-in HTTP detection
|
||||
|
||||
# If we haven't received enough data to identify the protocol after
|
||||
# 30 seconds, drop the connection
|
||||
tcp-request inspect-delay 30s
|
||||
|
||||
tcp-request content accept if rtmp_handshake_ver rtmp_handshake_size
|
||||
tcp-request content accept if HTTP
|
||||
|
||||
use_backend vertx if is_websocket
|
||||
use_backend red5 if rtmp_handshake_ver rtmp_handshake_size
|
||||
use_backend nginx if HTTP
|
||||
|
||||
backend nginx
|
||||
mode http
|
||||
option forwardfor
|
||||
reqadd X-Forwarded-Proto:\ https
|
||||
server nginx 127.0.0.1:80
|
||||
|
||||
backend red5
|
||||
mode tcp
|
||||
server red5 127.0.0.1:1935
|
||||
|
||||
backend vertx
|
||||
server vertx 127.0.0.1:3001
|
@ -1,13 +0,0 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name 192.168.23.33;
|
||||
|
||||
access_log /var/log/nginx/vertx-akka.access.log;
|
||||
|
||||
# Vertx-Akka landing page.
|
||||
location / {
|
||||
root /var/www/vertx-akka;
|
||||
index index.html index.htm;
|
||||
expires 1m;
|
||||
}
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
<!--
|
||||
#%L
|
||||
distributed-chat-service
|
||||
%%
|
||||
Copyright (C) 2015 Zanclus Consulting
|
||||
%%
|
||||
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.
|
||||
#L%
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Distributed Chat Service</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/sockjs/0.3.4/sockjs.min.js"></script>
|
||||
<script src="vertxbus.js"></script>
|
||||
<style>
|
||||
.inset {
|
||||
box-shadow: inset 0 0 4px #000000;
|
||||
-moz-box-shadow: inset 0 0 4px #000000;
|
||||
-webkit-box-shadow: inset 0 0 4px #000000;
|
||||
width: 400px;
|
||||
border-width: 4px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
input.inset {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
div.inset {
|
||||
height: 500px;
|
||||
white-space: pre-wrap
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
var eb = new vertx.EventBus("http://192.168.23.33:3001/eventbus");
|
||||
eb.onopen = function () {
|
||||
eb.registerHandler("chat.to.client", function (msg) {
|
||||
$('#chat').append(msg + "\n");
|
||||
});
|
||||
};
|
||||
|
||||
function send(event) {
|
||||
if (event.keyCode == 13 || event.which == 13) {
|
||||
var message = $('#input').val();
|
||||
if (message.length > 0) {
|
||||
console.log($('#input'));
|
||||
eb.publish("chat.to.server", message);
|
||||
$('#input').val("");
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<div id="chat" class="inset"></div>
|
||||
<input id="input" type="text" onkeydown="send(event)" class="inset">
|
||||
</body>
|
||||
</html>
|
@ -1,35 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
<script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/sockjs/0.3.4/sockjs.min.js"></script>
|
||||
<script src="vertxbus.js"></script>
|
||||
</head>
|
||||
|
||||
<style>
|
||||
.news {
|
||||
font-size: 20pt;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="news">Latest news: </div><br>
|
||||
<div id="status" class="news"></div>
|
||||
|
||||
<script>
|
||||
|
||||
var eb = new vertx.EventBus("http://192.168.23.33:3000/eventbus");
|
||||
|
||||
eb.onopen = function() {
|
||||
eb.registerHandler("news-feed", function(msg) {
|
||||
var str = "<code>" + msg + "</code><br>";
|
||||
$('#status').prepend(str);
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -1,228 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011-2013 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
|
||||
var vertx = vertx || {};
|
||||
|
||||
!function(factory) {
|
||||
if (typeof define === "function" && define.amd) {
|
||||
// Expose as an AMD module with SockJS dependency.
|
||||
// "vertxbus" and "sockjs" names are used because
|
||||
// AMD module names are derived from file names.
|
||||
define("vertxbus", ["sockjs"], factory);
|
||||
} else {
|
||||
// No AMD-compliant loader
|
||||
factory(SockJS);
|
||||
}
|
||||
}(function(SockJS) {
|
||||
|
||||
vertx.EventBus = function(url, options) {
|
||||
|
||||
var that = this;
|
||||
var sockJSConn = new SockJS(url, undefined, options);
|
||||
var handlerMap = {};
|
||||
var replyHandlers = {};
|
||||
var state = vertx.EventBus.CONNECTING;
|
||||
var pingTimerID = null;
|
||||
var pingInterval = null;
|
||||
if (options) {
|
||||
pingInterval = options['vertxbus_ping_interval'];
|
||||
}
|
||||
if (!pingInterval) {
|
||||
pingInterval = 5000;
|
||||
}
|
||||
|
||||
that.onopen = null;
|
||||
that.onclose = null;
|
||||
|
||||
that.send = function(address, message, replyHandler) {
|
||||
sendOrPub("send", address, message, replyHandler)
|
||||
}
|
||||
|
||||
that.publish = function(address, message) {
|
||||
sendOrPub("publish", address, message, null)
|
||||
}
|
||||
|
||||
that.registerHandler = function(address, handler) {
|
||||
checkSpecified("address", 'string', address);
|
||||
checkSpecified("handler", 'function', handler);
|
||||
checkOpen();
|
||||
var handlers = handlerMap[address];
|
||||
if (!handlers) {
|
||||
handlers = [handler];
|
||||
handlerMap[address] = handlers;
|
||||
// First handler for this address so we should register the connection
|
||||
var msg = { type : "register",
|
||||
address: address };
|
||||
sockJSConn.send(JSON.stringify(msg));
|
||||
} else {
|
||||
handlers[handlers.length] = handler;
|
||||
}
|
||||
}
|
||||
|
||||
that.unregisterHandler = function(address, handler) {
|
||||
checkSpecified("address", 'string', address);
|
||||
checkSpecified("handler", 'function', handler);
|
||||
checkOpen();
|
||||
var handlers = handlerMap[address];
|
||||
if (handlers) {
|
||||
var idx = handlers.indexOf(handler);
|
||||
if (idx != -1) handlers.splice(idx, 1);
|
||||
if (handlers.length == 0) {
|
||||
// No more local handlers so we should unregister the connection
|
||||
|
||||
var msg = { type : "unregister",
|
||||
address: address};
|
||||
sockJSConn.send(JSON.stringify(msg));
|
||||
delete handlerMap[address];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
that.close = function() {
|
||||
checkOpen();
|
||||
state = vertx.EventBus.CLOSING;
|
||||
sockJSConn.close();
|
||||
}
|
||||
|
||||
that.readyState = function() {
|
||||
return state;
|
||||
}
|
||||
|
||||
sockJSConn.onopen = function() {
|
||||
// Send the first ping then send a ping every pingInterval milliseconds
|
||||
sendPing();
|
||||
pingTimerID = setInterval(sendPing, pingInterval);
|
||||
state = vertx.EventBus.OPEN;
|
||||
if (that.onopen) {
|
||||
that.onopen();
|
||||
}
|
||||
};
|
||||
|
||||
sockJSConn.onclose = function() {
|
||||
state = vertx.EventBus.CLOSED;
|
||||
if (pingTimerID) clearInterval(pingTimerID);
|
||||
if (that.onclose) {
|
||||
that.onclose();
|
||||
}
|
||||
};
|
||||
|
||||
sockJSConn.onmessage = function(e) {
|
||||
var msg = e.data;
|
||||
var json = JSON.parse(msg);
|
||||
var type = json.type;
|
||||
if (type === 'err') {
|
||||
console.error("Error received on connection: " + json.body);
|
||||
return;
|
||||
}
|
||||
var body = json.body;
|
||||
var replyAddress = json.replyAddress;
|
||||
var address = json.address;
|
||||
var replyHandler;
|
||||
if (replyAddress) {
|
||||
replyHandler = function(reply, replyHandler) {
|
||||
// Send back reply
|
||||
that.send(replyAddress, reply, replyHandler);
|
||||
};
|
||||
}
|
||||
var handlers = handlerMap[address];
|
||||
if (handlers) {
|
||||
// We make a copy since the handler might get unregistered from within the
|
||||
// handler itself, which would screw up our iteration
|
||||
var copy = handlers.slice(0);
|
||||
for (var i = 0; i < copy.length; i++) {
|
||||
copy[i](body, replyHandler);
|
||||
}
|
||||
} else {
|
||||
// Might be a reply message
|
||||
var handler = replyHandlers[address];
|
||||
if (handler) {
|
||||
delete replyHandlers[address];
|
||||
handler(body, replyHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function sendPing() {
|
||||
var msg = {
|
||||
type: "ping"
|
||||
}
|
||||
sockJSConn.send(JSON.stringify(msg));
|
||||
}
|
||||
|
||||
function sendOrPub(sendOrPub, address, message, replyHandler) {
|
||||
checkSpecified("address", 'string', address);
|
||||
checkSpecified("replyHandler", 'function', replyHandler, true);
|
||||
checkOpen();
|
||||
var envelope = { type : sendOrPub,
|
||||
address: address,
|
||||
body: message };
|
||||
if (replyHandler) {
|
||||
var replyAddress = makeUUID();
|
||||
envelope.replyAddress = replyAddress;
|
||||
replyHandlers[replyAddress] = replyHandler;
|
||||
}
|
||||
var str = JSON.stringify(envelope);
|
||||
sockJSConn.send(str);
|
||||
}
|
||||
|
||||
function checkOpen() {
|
||||
if (state != vertx.EventBus.OPEN) {
|
||||
throw new Error('INVALID_STATE_ERR');
|
||||
}
|
||||
}
|
||||
|
||||
function checkSpecified(paramName, paramType, param, optional) {
|
||||
if (!optional && !param) {
|
||||
throw new Error("Parameter " + paramName + " must be specified");
|
||||
}
|
||||
if (param && typeof param != paramType) {
|
||||
throw new Error("Parameter " + paramName + " must be of type " + paramType);
|
||||
}
|
||||
}
|
||||
|
||||
function isFunction(obj) {
|
||||
return !!(obj && obj.constructor && obj.call && obj.apply);
|
||||
}
|
||||
|
||||
function makeUUID(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
|
||||
.replace(/[xy]/g,function(a,b){return b=Math.random()*16,(a=="y"?b&3|8:b|0).toString(16)})}
|
||||
|
||||
}
|
||||
|
||||
vertx.EventBus.CONNECTING = 0;
|
||||
vertx.EventBus.OPEN = 1;
|
||||
vertx.EventBus.CLOSING = 2;
|
||||
vertx.EventBus.CLOSED = 3;
|
||||
|
||||
return vertx.EventBus;
|
||||
|
||||
});
|
@ -1,99 +0,0 @@
|
||||
package org.bigbluebutton.build
|
||||
|
||||
import sbt._
|
||||
import Keys._
|
||||
|
||||
object Dependencies {
|
||||
|
||||
object Versions {
|
||||
// Scala
|
||||
val scala = "2.12.8"
|
||||
val junit = "4.12"
|
||||
val junitInterface = "0.11"
|
||||
val scalactic = "3.0.3"
|
||||
|
||||
// Libraries
|
||||
val akkaVersion = "2.5.19"
|
||||
val gson = "2.8.5"
|
||||
val jackson = "2.9.7"
|
||||
val logback = "1.2.3"
|
||||
val quicklens = "1.4.11"
|
||||
val spray = "1.3.4"
|
||||
val vertxV = "3.5.1"
|
||||
|
||||
// Apache Commons
|
||||
val lang = "3.8.1"
|
||||
val codec = "1.11"
|
||||
|
||||
// BigBlueButton
|
||||
val bbbCommons = "0.0.20-SNAPSHOT"
|
||||
|
||||
// Test
|
||||
val scalaTest = "3.0.5"
|
||||
val mockito = "2.23.0"
|
||||
val akkaTestKit = "2.5.18"
|
||||
}
|
||||
|
||||
object Compile {
|
||||
val scalaLibrary = "org.scala-lang" % "scala-library" % Versions.scala
|
||||
val scalaCompiler = "org.scala-lang" % "scala-compiler" % Versions.scala
|
||||
|
||||
val akkaActor = "com.typesafe.akka" % "akka-actor_2.12" % Versions.akkaVersion
|
||||
val akkaSl4fj = "com.typesafe.akka" % "akka-slf4j_2.12" % Versions.akkaVersion
|
||||
|
||||
val vertxWeb = "io.vertx" % "vertx-web" % Versions.vertxV
|
||||
val vertxAuthCommon = "io.vertx" % "vertx-auth-common" % Versions.vertxV
|
||||
val vertxAuthShiro = "io.vertx" % "vertx-auth-shiro" % Versions.vertxV
|
||||
val vertxWebScala = "io.vertx" %% "vertx-web-scala" % Versions.vertxV
|
||||
val vertxLangScala = "io.vertx" %% "vertx-lang-scala" % Versions.vertxV
|
||||
|
||||
val googleGson = "com.google.code.gson" % "gson" % Versions.gson
|
||||
val jacksonModule = "com.fasterxml.jackson.module" %% "jackson-module-scala" % Versions.jackson
|
||||
val quicklens = "com.softwaremill.quicklens" %% "quicklens" % Versions.quicklens
|
||||
val logback = "ch.qos.logback" % "logback-classic" % Versions.logback
|
||||
val commonsCodec = "commons-codec" % "commons-codec" % Versions.codec
|
||||
val sprayJson = "io.spray" % "spray-json_2.12" % Versions.spray
|
||||
|
||||
val redisEtaty = "com.github.etaty" % "rediscala_2.12" % "1.8.0"
|
||||
|
||||
val apacheLang = "org.apache.commons" % "commons-lang3" % Versions.lang
|
||||
|
||||
val bbbCommons = "org.bigbluebutton" % "bbb-common-message_2.12" % Versions.bbbCommons excludeAll (
|
||||
ExclusionRule(organization = "org.red5"))
|
||||
}
|
||||
|
||||
object Test {
|
||||
val scalaTest = "org.scalatest" %% "scalatest" % Versions.scalaTest % "test"
|
||||
val junit = "junit" % "junit" % Versions.junit % "test"
|
||||
val mockitoCore = "org.mockito" % "mockito-core" % Versions.mockito % "test"
|
||||
val scalactic = "org.scalactic" % "scalactic_2.12" % Versions.scalactic % "test"
|
||||
val akkaTestKit = "com.typesafe.akka" %% "akka-testkit" % Versions.akkaTestKit % "test"
|
||||
}
|
||||
|
||||
val testing = Seq(
|
||||
Test.scalaTest,
|
||||
Test.junit,
|
||||
Test.mockitoCore,
|
||||
Test.scalactic,
|
||||
Test.akkaTestKit)
|
||||
|
||||
val runtime = Seq(
|
||||
Compile.scalaLibrary,
|
||||
Compile.scalaCompiler,
|
||||
Compile.akkaActor,
|
||||
Compile.akkaSl4fj,
|
||||
Compile.vertxWeb,
|
||||
Compile.vertxAuthCommon,
|
||||
Compile.vertxAuthShiro,
|
||||
Compile.vertxWebScala,
|
||||
Compile.vertxWebScala,
|
||||
Compile.googleGson,
|
||||
Compile.jacksonModule,
|
||||
Compile.quicklens,
|
||||
Compile.logback,
|
||||
Compile.commonsCodec,
|
||||
Compile.sprayJson,
|
||||
Compile.apacheLang,
|
||||
Compile.redisEtaty,
|
||||
Compile.bbbCommons) ++ testing
|
||||
}
|
@ -1 +0,0 @@
|
||||
sbt.version=1.2.7
|
@ -1 +0,0 @@
|
||||
|
@ -1,11 +0,0 @@
|
||||
addSbtPlugin("io.spray" % "sbt-revolver" % "0.9.1")
|
||||
|
||||
addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "5.2.4")
|
||||
|
||||
addSbtPlugin("org.scalariform" % "sbt-scalariform" % "1.8.2")
|
||||
|
||||
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.3.15")
|
||||
|
||||
addSbtPlugin("net.vonbuchholtz" % "sbt-dependency-check" % "0.2.9")
|
||||
|
||||
addSbtPlugin("org.scalastyle" %% "scalastyle-sbt-plugin" % "1.0.0")
|
@ -1,6 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
rm -rf src/main/resources
|
||||
cp -R src/universal/conf src/main/resources
|
||||
sbt run
|
||||
|
@ -1,6 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
sbt clean stage
|
||||
sudo service bbb-vertx-akka stop
|
||||
cd target/universal/stage
|
||||
./bin/bbb-vertx-akka
|
Binary file not shown.
@ -1,12 +0,0 @@
|
||||
package org.bigbluebutton.client;
|
||||
|
||||
|
||||
import org.bigbluebutton.client.bus.ConnInfo2;
|
||||
|
||||
public interface IClientInGW {
|
||||
void connect(ConnInfo2 connInfo);
|
||||
void disconnect(ConnInfo2 connInfo);
|
||||
void handleMsgFromClient(ConnInfo2 connInfo, String json);
|
||||
void send(String channel, String json);
|
||||
}
|
||||
|
@ -1,46 +0,0 @@
|
||||
/**
|
||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||
*
|
||||
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package org.bigbluebutton.red5.client.messaging;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class BroadcastClientMessage implements ClientMessage {
|
||||
|
||||
private String meetingID;
|
||||
private Map<String, Object> message;
|
||||
private String messageName;
|
||||
|
||||
public BroadcastClientMessage(String meetingID, String messageName, Map<String, Object> message) {
|
||||
this.meetingID = meetingID;
|
||||
this.message = message;
|
||||
this.messageName = messageName;
|
||||
}
|
||||
|
||||
public String getMeetingID() {
|
||||
return meetingID;
|
||||
}
|
||||
|
||||
public String getMessageName() {
|
||||
return messageName;
|
||||
}
|
||||
|
||||
public Map<String, Object> getMessage() {
|
||||
return message;
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
package org.bigbluebutton.red5.client.messaging;
|
||||
|
||||
|
||||
public class BroadcastToMeetingMsg implements ClientMessage {
|
||||
|
||||
public final String meetingId;
|
||||
public final String messageName;
|
||||
public final String json;
|
||||
|
||||
public BroadcastToMeetingMsg(String meetingId, String messageName, String json) {
|
||||
this.meetingId = meetingId;
|
||||
this.messageName = messageName;
|
||||
this.json = json;
|
||||
}
|
||||
|
||||
public String getMessageName() {
|
||||
return messageName;
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
/**
|
||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||
*
|
||||
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package org.bigbluebutton.red5.client.messaging;
|
||||
|
||||
|
||||
public interface ClientMessage {
|
||||
|
||||
String getMessageName();
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
package org.bigbluebutton.red5.client.messaging;
|
||||
|
||||
|
||||
public class CloseConnectionMsg implements ClientMessage {
|
||||
|
||||
public final String meetingId;
|
||||
public final String connId;
|
||||
|
||||
public CloseConnectionMsg(String meetingId, String connId) {
|
||||
this.meetingId = meetingId;
|
||||
this.connId = connId;
|
||||
}
|
||||
|
||||
public String getMessageName() {
|
||||
return "CloseConnectionMsg";
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
package org.bigbluebutton.red5.client.messaging;
|
||||
|
||||
|
||||
public class CloseMeetingAllConnectionsMsg implements ClientMessage {
|
||||
|
||||
public final String meetingId;
|
||||
|
||||
public CloseMeetingAllConnectionsMsg(String meetingId) {
|
||||
this.meetingId = meetingId;
|
||||
}
|
||||
|
||||
public String getMessageName() {
|
||||
return "CloseMeetingAllConnectionsMsg";
|
||||
}
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
/**
|
||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||
*
|
||||
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package org.bigbluebutton.red5.client.messaging;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class DirectClientMessage implements ClientMessage {
|
||||
|
||||
private String meetingID;
|
||||
private String userID;
|
||||
private Map<String, Object> message;
|
||||
private String messageName;
|
||||
private String sharedObjectName;
|
||||
|
||||
public DirectClientMessage(String meetingID, String userID, String messageName, Map<String, Object> message) {
|
||||
this.meetingID = meetingID;
|
||||
this.userID = userID;
|
||||
this.message = message;
|
||||
this.messageName = messageName;
|
||||
}
|
||||
|
||||
public void setSharedObjectName(String name) {
|
||||
sharedObjectName = name;
|
||||
}
|
||||
|
||||
public String getSharedObjectName() {
|
||||
return sharedObjectName;
|
||||
}
|
||||
|
||||
public String getMeetingID() {
|
||||
return meetingID;
|
||||
}
|
||||
|
||||
public String getUserID() {
|
||||
return userID;
|
||||
}
|
||||
|
||||
public String getMessageName() {
|
||||
return messageName;
|
||||
}
|
||||
|
||||
public Map<String, Object> getMessage() {
|
||||
return message;
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
package org.bigbluebutton.red5.client.messaging;
|
||||
|
||||
|
||||
public class DirectToClientMsg implements ClientMessage{
|
||||
public final String meetingId;
|
||||
public final String connId;
|
||||
public final String json;
|
||||
public final String messageName;
|
||||
|
||||
public DirectToClientMsg(String meetingId, String connId, String messageName, String json) {
|
||||
this.meetingId = meetingId;
|
||||
this.connId = connId;
|
||||
this.messageName = messageName;
|
||||
this.json = json;
|
||||
}
|
||||
|
||||
public String getMessageName() {
|
||||
return messageName;
|
||||
}
|
||||
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
package org.bigbluebutton.red5.client.messaging;
|
||||
|
||||
public class DisconnectAllClientsMessage implements ClientMessage {
|
||||
|
||||
private final String meetingId;
|
||||
|
||||
public DisconnectAllClientsMessage(String meetingId) {
|
||||
this.meetingId = meetingId;
|
||||
}
|
||||
|
||||
public String getMeetingId() {
|
||||
return meetingId;
|
||||
}
|
||||
|
||||
public String getMessageName() {
|
||||
return "DisconnectAllClientsMessage";
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
package org.bigbluebutton.red5.client.messaging;
|
||||
|
||||
public class DisconnectAllMessage implements ClientMessage {
|
||||
|
||||
public String getMessageName() {
|
||||
return "DisconnectAllMessage";
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
package org.bigbluebutton.red5.client.messaging;
|
||||
|
||||
public class DisconnectClientMessage implements ClientMessage {
|
||||
|
||||
private final String meetingId;
|
||||
private final String userId;
|
||||
|
||||
public DisconnectClientMessage(String meetingId, String userId) {
|
||||
this.meetingId = meetingId;
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getMeetingId() {
|
||||
return meetingId;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public String getMessageName() {
|
||||
return "DisconnectClientMessage";
|
||||
}
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
package org.bigbluebutton.red5.client.messaging;
|
||||
|
||||
|
||||
public interface IConnectionInvokerService {
|
||||
void sendMessage(final ClientMessage message);
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
/**
|
||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||
*
|
||||
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package org.bigbluebutton.red5.client.messaging;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class SharedObjectClientMessage implements ClientMessage {
|
||||
public static final String BROADCAST = "broadcast";
|
||||
public static final String DIRECT = "direct";
|
||||
public static final String SHAREDOBJECT = "sharedobject";
|
||||
|
||||
private String meetingID;
|
||||
private String sharedObjectName;
|
||||
private ArrayList<Object> message;
|
||||
private String messageName;
|
||||
|
||||
public SharedObjectClientMessage(String meetingID, String sharedObjectName, String messageName, ArrayList<Object> message) {
|
||||
this.meetingID = meetingID;
|
||||
this.message = message;
|
||||
this.sharedObjectName = sharedObjectName;
|
||||
this.messageName = messageName;
|
||||
}
|
||||
|
||||
public void setSharedObjectName(String name) {
|
||||
sharedObjectName = name;
|
||||
}
|
||||
|
||||
public String getSharedObjectName() {
|
||||
return sharedObjectName;
|
||||
}
|
||||
|
||||
public String getMeetingID() {
|
||||
return meetingID;
|
||||
}
|
||||
|
||||
public String getMessageName() {
|
||||
return messageName;
|
||||
}
|
||||
|
||||
public ArrayList<Object> getMessage() {
|
||||
return message;
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
package org.bigbluebutton.vertx;
|
||||
|
||||
import io.vertx.core.Vertx;
|
||||
|
||||
public class AkkaToVertxGateway implements IAkkaToVertxGateway{
|
||||
|
||||
private final Vertx vertx;
|
||||
|
||||
public AkkaToVertxGateway(Vertx vertx) {
|
||||
this.vertx = vertx;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(String json) {
|
||||
vertx.eventBus().publish("to-vertx", json);
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
package org.bigbluebutton.vertx;
|
||||
|
||||
import io.vertx.core.AbstractVerticle;
|
||||
import io.vertx.ext.auth.AuthProvider;
|
||||
import io.vertx.ext.web.Router;
|
||||
import io.vertx.ext.web.handler.*;
|
||||
import io.vertx.ext.web.sstore.LocalSessionStore;
|
||||
import org.bigbluebutton.VertxToAkkaGateway;
|
||||
|
||||
public class AuthenticateVerticle extends AbstractVerticle {
|
||||
private final VertxToAkkaGateway gw;
|
||||
|
||||
public AuthenticateVerticle(VertxToAkkaGateway gw) {
|
||||
this.gw = gw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() throws Exception {
|
||||
|
||||
Router router = Router.router(vertx);
|
||||
|
||||
// We need cookies, sessions and request bodies
|
||||
router.route().handler(CookieHandler.create());
|
||||
router.route().handler(BodyHandler.create());
|
||||
router.route().handler(SessionHandler.create(LocalSessionStore.create(vertx)));
|
||||
|
||||
// Simple auth service which uses a properties file for user/role info
|
||||
AuthProvider authProvider = new MyAuthProvider(vertx);
|
||||
|
||||
// We need a user session handler too to make sure the user is stored in the session between requests
|
||||
router.route().handler(UserSessionHandler.create(authProvider));
|
||||
|
||||
// Any requests to URI starting '/private/' require login
|
||||
router.route("/private/*").handler(RedirectAuthHandler.create(authProvider, "/loginpage.html"));
|
||||
|
||||
// Serve the static private pages from directory 'private'
|
||||
router.route("/private/*").handler(StaticHandler.create().setCachingEnabled(false).setWebRoot("private"));
|
||||
|
||||
// Handles the actual login
|
||||
router.route("/loginhandler").handler(FormLoginHandler.create(authProvider));
|
||||
|
||||
// Implement logout
|
||||
router.route("/logout").handler(context -> {
|
||||
context.clearUser();
|
||||
// Redirect back to the index page
|
||||
context.response().putHeader("location", "/").setStatusCode(302).end();
|
||||
});
|
||||
|
||||
// Serve the non private static pages
|
||||
router.route().handler(StaticHandler.create());
|
||||
|
||||
vertx.createHttpServer().requestHandler(router::accept).listen(4000);
|
||||
}
|
||||
}
|
@ -1,91 +0,0 @@
|
||||
package org.bigbluebutton.vertx;
|
||||
|
||||
import io.vertx.core.AbstractVerticle;
|
||||
import io.vertx.core.MultiMap;
|
||||
import io.vertx.core.http.HttpServerResponse;
|
||||
import io.vertx.core.json.JsonArray;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.ext.web.Router;
|
||||
import io.vertx.ext.web.RoutingContext;
|
||||
import io.vertx.ext.web.handler.BodyHandler;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="http://tfox.org">Tim Fox</a>
|
||||
*/
|
||||
public class BbbApi extends AbstractVerticle {
|
||||
|
||||
|
||||
private Map<String, JsonObject> products = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
|
||||
setUpInitialData();
|
||||
|
||||
Router router = Router.router(vertx);
|
||||
|
||||
router.route().handler(BodyHandler.create());
|
||||
router.get("/products/:productID").handler(this::handleGetProduct);
|
||||
router.put("/products/:productID").handler(this::handleAddProduct);
|
||||
router.get("/products").handler(this::handleListProducts);
|
||||
router.get("/bigbluebutton/api/create").handler(this::handleListProducts);
|
||||
|
||||
vertx.createHttpServer().requestHandler(router::accept).listen(4000);
|
||||
}
|
||||
|
||||
private void handleGetProduct(RoutingContext routingContext) {
|
||||
String productID = routingContext.request().getParam("productID");
|
||||
HttpServerResponse response = routingContext.response();
|
||||
if (productID == null) {
|
||||
sendError(400, response);
|
||||
} else {
|
||||
JsonObject product = products.get(productID);
|
||||
if (product == null) {
|
||||
sendError(404, response);
|
||||
} else {
|
||||
response.putHeader("content-type", "application/json").end(product.encodePrettily());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleAddProduct(RoutingContext routingContext) {
|
||||
String productID = routingContext.request().getParam("productID");
|
||||
HttpServerResponse response = routingContext.response();
|
||||
if (productID == null) {
|
||||
sendError(400, response);
|
||||
} else {
|
||||
JsonObject product = routingContext.getBodyAsJson();
|
||||
if (product == null) {
|
||||
sendError(400, response);
|
||||
} else {
|
||||
products.put(productID, product);
|
||||
response.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleListProducts(RoutingContext routingContext) {
|
||||
MultiMap params = routingContext.request().params();
|
||||
System.out.println("Name: " + params.get("name"));
|
||||
JsonArray arr = new JsonArray();
|
||||
products.forEach((k, v) -> arr.add(v));
|
||||
routingContext.response().putHeader("content-type", "application/json").end(arr.encodePrettily());
|
||||
}
|
||||
|
||||
private void sendError(int statusCode, HttpServerResponse response) {
|
||||
response.setStatusCode(statusCode).end();
|
||||
}
|
||||
|
||||
private void setUpInitialData() {
|
||||
addProduct(new JsonObject().put("id", "prod3568").put("name", "Egg Whisk").put("price", 3.99).put("weight", 150));
|
||||
addProduct(new JsonObject().put("id", "prod7340").put("name", "Tea Cosy").put("price", 5.99).put("weight", 100));
|
||||
addProduct(new JsonObject().put("id", "prod8643").put("name", "Spatula").put("price", 1.00).put("weight", 80));
|
||||
}
|
||||
|
||||
private void addProduct(JsonObject product) {
|
||||
products.put(product.getString("id"), product);
|
||||
}
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
package org.bigbluebutton.vertx;
|
||||
|
||||
import io.vertx.core.AsyncResult;
|
||||
import io.vertx.core.Handler;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.core.json.JsonArray;
|
||||
import io.vertx.ext.auth.AbstractUser;
|
||||
import io.vertx.ext.auth.AuthProvider;
|
||||
import io.vertx.core.logging.Logger;
|
||||
import io.vertx.core.logging.LoggerFactory;
|
||||
import io.vertx.core.Future;
|
||||
|
||||
public class BbbUser extends AbstractUser {
|
||||
private static final Logger log = LoggerFactory.getLogger(BbbUser.class);
|
||||
|
||||
private JsonObject jwtToken;
|
||||
private JsonArray permissions;
|
||||
|
||||
public BbbUser(JsonObject jwtToken, JsonArray permissions) {
|
||||
this.jwtToken = jwtToken;
|
||||
this.permissions = permissions;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public JsonObject principal() {
|
||||
return jwtToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuthProvider(AuthProvider arg0) {
|
||||
// NOOP - JWT tokens are self contained :)
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doIsPermitted(String permission, Handler<AsyncResult<Boolean>> handler) {
|
||||
if (permissions != null) {
|
||||
for (Object jwtPermission : permissions) {
|
||||
if (permission.equals(jwtPermission)) {
|
||||
handler.handle(Future.succeededFuture(true));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.debug("User has no permission [" + permission + "]");
|
||||
handler.handle(Future.succeededFuture(false));
|
||||
}
|
||||
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
package org.bigbluebutton.vertx;
|
||||
|
||||
import io.vertx.core.AbstractVerticle;
|
||||
import io.vertx.core.eventbus.EventBus;
|
||||
import io.vertx.ext.web.Router;
|
||||
import io.vertx.ext.web.handler.StaticHandler;
|
||||
import io.vertx.ext.bridge.BridgeEventType;
|
||||
import io.vertx.ext.web.handler.sockjs.BridgeOptions;
|
||||
import io.vertx.ext.web.handler.sockjs.PermittedOptions;
|
||||
import io.vertx.ext.web.handler.sockjs.SockJSHandler;
|
||||
import io.vertx.ext.web.handler.sockjs.SockJSHandlerOptions;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.time.Instant;
|
||||
import java.util.Date;
|
||||
|
||||
import org.bigbluebutton.VertxToAkkaGateway;
|
||||
|
||||
|
||||
public class ChatVerticle extends AbstractVerticle {
|
||||
|
||||
private final VertxToAkkaGateway gw;
|
||||
|
||||
public ChatVerticle(VertxToAkkaGateway gw) {
|
||||
this.gw = gw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() throws Exception {
|
||||
|
||||
Router router = Router.router(vertx);
|
||||
|
||||
// Allow events for the designated addresses in/out of the event bus bridge
|
||||
BridgeOptions opts = new BridgeOptions()
|
||||
.addInboundPermitted(new PermittedOptions().setAddress("chat.to.server"))
|
||||
.addOutboundPermitted(new PermittedOptions().setAddress("chat.to.client"));
|
||||
|
||||
SockJSHandlerOptions options = new SockJSHandlerOptions().setHeartbeatInterval(2000);
|
||||
|
||||
// Create the event bus bridge and add it to the router.
|
||||
SockJSHandler ebHandler = SockJSHandler.create(vertx, options);
|
||||
router.route("/eventbus/*").handler(ebHandler);
|
||||
|
||||
// Create a router endpoint for the static content.
|
||||
router.route().handler(StaticHandler.create());
|
||||
|
||||
ebHandler.bridge(opts, be -> {
|
||||
if (be.type() == BridgeEventType.PUBLISH || be.type() == BridgeEventType.RECEIVE) {
|
||||
if (be.getRawMessage().getString("body").equals("armadillos")) {
|
||||
// Reject it
|
||||
be.complete(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
be.complete(true);
|
||||
});
|
||||
|
||||
// Start the web server and tell it to use the router to handle requests.
|
||||
vertx.createHttpServer().requestHandler(router::accept).listen(3001);
|
||||
|
||||
EventBus eb = vertx.eventBus();
|
||||
|
||||
// Register to listen for messages coming IN to the server
|
||||
eb.consumer("chat.to.server").handler(message -> {
|
||||
// Create a timestamp string
|
||||
String timestamp = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM).format(Date.from(Instant.now()));
|
||||
// Send the message back out to all clients with the timestamp prepended.
|
||||
gw.send(timestamp + ": " + message.body());
|
||||
});
|
||||
|
||||
eb.consumer("to-vertx").handler(message -> {
|
||||
eb.publish("chat.to.client", message.body());
|
||||
});
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
package org.bigbluebutton.vertx;
|
||||
|
||||
import org.bigbluebutton.ConnectionManager;
|
||||
import org.bigbluebutton.VertxToAkkaGateway;
|
||||
|
||||
import io.vertx.core.Vertx;
|
||||
|
||||
public class HelloWorld {
|
||||
|
||||
private final Vertx vertx;
|
||||
private final VertxToAkkaGateway gw;
|
||||
private final ConnectionManager cm;
|
||||
|
||||
public HelloWorld(Vertx vertx, VertxToAkkaGateway gw, ConnectionManager cm) {
|
||||
this.vertx = vertx;
|
||||
this.gw = gw;
|
||||
this.cm = cm;
|
||||
}
|
||||
|
||||
public void startup() {
|
||||
// Create an HTTP server which simply returns "Hello World!" to each request.
|
||||
//Vertx.vertx().createHttpServer().requestHandler(req -> req.response().end("Hello World! from gradle.")).listen(3000);
|
||||
|
||||
//vertx.deployVerticle(new ChatVerticle(gw));
|
||||
//vertx.deployVerticle(new RealtimeVerticle());
|
||||
//vertx.deployVerticle(new AuthenticateVerticle());
|
||||
|
||||
//vertx.deployVerticle(new PrivateVerticle(gw));
|
||||
vertx.deployVerticle(new SockJSHandlerVerticle(cm));
|
||||
//vertx.deployVerticle(new SimpleREST());
|
||||
//vertx.deployVerticle(new BbbApi());
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
package org.bigbluebutton.vertx;
|
||||
|
||||
public interface IAkkaToVertxGateway {
|
||||
|
||||
void send(String json);
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
package org.bigbluebutton.vertx;
|
||||
|
||||
public interface IVertxToAkkaGateway {
|
||||
|
||||
void send(String json);
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
package org.bigbluebutton.vertx;
|
||||
|
||||
import org.bigbluebutton.VertxToAkkaGateway;
|
||||
|
||||
import io.vertx.core.AsyncResult;
|
||||
import io.vertx.core.Handler;
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.core.eventbus.DeliveryOptions;
|
||||
import io.vertx.core.json.JsonArray;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.ext.auth.AuthProvider;
|
||||
import io.vertx.ext.auth.User;
|
||||
import io.vertx.core.Future;
|
||||
|
||||
public class MyAuthProvider implements AuthProvider {
|
||||
|
||||
private final Vertx vertx;
|
||||
|
||||
public MyAuthProvider(Vertx vertx) {
|
||||
this.vertx = vertx;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void authenticate(JsonObject user, Handler<AsyncResult<User>> resultHandler) {
|
||||
JsonObject object = new JsonObject();
|
||||
object.put("foo", "bar").put("num", 123).put("mybool", true);
|
||||
|
||||
JsonArray array = new JsonArray();
|
||||
array.add("foo").add(123).add(false);
|
||||
|
||||
DeliveryOptions options = new DeliveryOptions();
|
||||
options.setSendTimeout(5000);
|
||||
|
||||
vertx.eventBus().send("to-akka-gw",
|
||||
"Yay! Someone kicked a ball across a patch of grass",
|
||||
options, ar -> {
|
||||
if (ar.succeeded()) {
|
||||
System.out.println("Received reply: " + ar.result().body());
|
||||
System.out.println("Got Authenticated");
|
||||
resultHandler.handle(Future.succeededFuture(new BbbUser(object, array)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -1,169 +0,0 @@
|
||||
package org.bigbluebutton.vertx;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.time.Instant;
|
||||
import java.util.Date;
|
||||
|
||||
import org.bigbluebutton.VertxToAkkaGateway;
|
||||
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.core.AbstractVerticle;
|
||||
import io.vertx.core.eventbus.EventBus;
|
||||
import io.vertx.core.http.HttpServerOptions;
|
||||
import io.vertx.core.net.JksOptions;
|
||||
import io.vertx.ext.auth.AuthProvider;
|
||||
import io.vertx.ext.web.Router;
|
||||
import io.vertx.ext.web.Session;
|
||||
import io.vertx.ext.web.handler.*;
|
||||
import io.vertx.ext.bridge.BridgeEventType;
|
||||
import io.vertx.ext.web.handler.sockjs.BridgeOptions;
|
||||
import io.vertx.ext.web.handler.sockjs.PermittedOptions;
|
||||
import io.vertx.ext.web.handler.sockjs.SockJSHandler;
|
||||
import io.vertx.ext.web.handler.sockjs.SockJSHandlerOptions;
|
||||
import io.vertx.ext.web.sstore.LocalSessionStore;
|
||||
|
||||
public class PrivateVerticle extends AbstractVerticle {
|
||||
private final VertxToAkkaGateway gw;
|
||||
|
||||
public PrivateVerticle(VertxToAkkaGateway gw) {
|
||||
this.gw = gw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() throws Exception {
|
||||
|
||||
Router router = Router.router(vertx);
|
||||
|
||||
// We need cookies, sessions and request bodies
|
||||
router.route().handler(CookieHandler.create());
|
||||
router.route().handler(BodyHandler.create());
|
||||
router.route().handler(SessionHandler.create(LocalSessionStore.create(vertx)));
|
||||
|
||||
// Simple auth service which uses a properties file for user/role info
|
||||
//AuthProvider authProvider = new MyAuthProvider(vertx);
|
||||
|
||||
// We need a user session handler too to make sure the user is stored in the session between requests
|
||||
//router.route().handler(UserSessionHandler.create(authProvider));
|
||||
|
||||
// Handles the actual login
|
||||
//router.route("/loginhandler").handler(FormLoginHandler.create(authProvider));
|
||||
|
||||
router.route("/private/*").handler(routingContext -> {
|
||||
|
||||
// This will require a login
|
||||
|
||||
// This will have the value true
|
||||
boolean isAuthenticated = routingContext.user() != null;
|
||||
|
||||
if (isAuthenticated) {
|
||||
System.out.println("**** User is authenticated.");
|
||||
} else {
|
||||
System.out.println("**** User is NOT authenticated.");
|
||||
}
|
||||
Session session = routingContext.session();
|
||||
|
||||
Integer cnt = session.get("hitcount");
|
||||
cnt = (cnt == null ? 0 : cnt) + 1;
|
||||
|
||||
session.put("hitcount", cnt);
|
||||
|
||||
// routingContext.response().putHeader("content-type", "text/html")
|
||||
// .end("<html><body><h1>Hitcount: " + cnt + "</h1></body></html>");
|
||||
routingContext.next();
|
||||
|
||||
});
|
||||
|
||||
// Any requests to URI starting '/private/' require login
|
||||
//router.route("/private/*").handler(RedirectAuthHandler.create(authProvider, "/loginpage.html"));
|
||||
|
||||
// Serve the static private pages from directory 'private'
|
||||
//router.route("/private/*").handler(StaticHandler.create().setCachingEnabled(false).setWebRoot("private"));
|
||||
|
||||
// Implement logout
|
||||
router.route("/logout").handler(context -> {
|
||||
context.clearUser();
|
||||
// Redirect back to the index page
|
||||
context.response().putHeader("location", "/").setStatusCode(302).end();
|
||||
});
|
||||
|
||||
// Allow events for the designated addresses in/out of the event bus bridge
|
||||
BridgeOptions opts = new BridgeOptions()
|
||||
.addInboundPermitted(new PermittedOptions().setAddress("chat.to.server"))
|
||||
.addOutboundPermitted(new PermittedOptions().setAddress("chat.to.client"));
|
||||
|
||||
SockJSHandlerOptions options = new SockJSHandlerOptions().setHeartbeatInterval(2000);
|
||||
|
||||
// Create the event bus bridge and add it to the router.
|
||||
SockJSHandler sockJSHandler = SockJSHandler.create(vertx, options);
|
||||
|
||||
router.route("/eventbus/*").handler(sockJSHandler);
|
||||
|
||||
// SockJSHandlerFactory sockJsMessageHandler = new SockJSHandlerFactory();
|
||||
// sockJsMessageHandler.setupHandler(ebHandler, opts);
|
||||
|
||||
EventBus eb = vertx.eventBus();
|
||||
|
||||
sockJSHandler.bridge(opts, be -> {
|
||||
if (be.type() == BridgeEventType.SOCKET_CREATED) {
|
||||
System.out.println("Socket create for session: " + be.socket().webSession().id() + " socketWriteId:" + be.socket().writeHandlerID());
|
||||
} else if (be.type() == BridgeEventType.SOCKET_CLOSED) {
|
||||
System.out.println("Socket closed for: " + be.socket().webSession().id() + " \n " + be.getRawMessage());
|
||||
// } else if (be.type() == BridgeEventType.SOCKET_IDLE) {
|
||||
// System.out.println("Socket SOCKET_IDLE for: " + be.socket().webSession().id());
|
||||
// } else if (be.type() == BridgeEventType.SOCKET_PING) {
|
||||
// System.out.println("Socket SOCKET_PING for: " + be.socket().webSession().id());
|
||||
} else if (be.type() == BridgeEventType.UNREGISTER) {
|
||||
System.out.println("Socket UNREGISTER for: " + be.socket().webSession().id() + " \n " + be.getRawMessage());
|
||||
} else if (be.type() == BridgeEventType.PUBLISH) {
|
||||
System.out.println("Socket PUBLISH for: " + be.socket().webSession().id() + " \n " + be.getRawMessage());
|
||||
} else if (be.type() == BridgeEventType.RECEIVE) {
|
||||
System.out.println("Socket RECEIVE for: " + be.socket().webSession().id() + " \n " + be.getRawMessage());
|
||||
} else if (be.type() == BridgeEventType.SEND) {
|
||||
System.out.println("Socket SEND for: " + be.socket().webSession().id() + " \n " + be.getRawMessage());
|
||||
} else if (be.type() == BridgeEventType.REGISTER) {
|
||||
System.out.println("Socket REGISTER for: " + be.socket().webSession().id() + " \n " + be.getRawMessage());
|
||||
eb.consumer("to-vertx").handler(message -> {
|
||||
System.out.println("**** response to " + be.socket().webSession().id() + " msg = " + message.body());
|
||||
if (message.body().toString().equals("CLOSE_SOCKET")) {
|
||||
be.socket().close();
|
||||
}
|
||||
});
|
||||
//gw.send(be.rawMessage().toString());
|
||||
} else {
|
||||
System.out.println("Message from: " + be.socket().webSession().id() + " \n " + be.getRawMessage());
|
||||
}
|
||||
|
||||
// System.out.println("USER=" + be.socket().webUser().principal());
|
||||
|
||||
be.complete(true);
|
||||
});
|
||||
|
||||
// Create a router endpoint for the static content.
|
||||
router.route().handler(StaticHandler.create());
|
||||
|
||||
// Start the web server and tell it to use the router to handle requests.
|
||||
//vertx.createHttpServer(new HttpServerOptions().setSsl(true).setKeyStoreOptions(
|
||||
// new JksOptions().setPath("server-keystore.jks").setPassword("wibble")
|
||||
// )).requestHandler(router::accept).listen(3001);
|
||||
vertx.createHttpServer().requestHandler(router::accept).listen(3001);
|
||||
|
||||
// Register to listen for messages coming IN to the server
|
||||
eb.consumer("chat.to.server").handler(message -> {
|
||||
// Create a timestamp string
|
||||
String timestamp = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM).format(Date.from(Instant.now()));
|
||||
// Send the message back out to all clients with the timestamp prepended.
|
||||
gw.send("TO ECHO:" + timestamp + ": " + message.body());
|
||||
// eb.publish("foofoofoo", message.body());
|
||||
});
|
||||
|
||||
eb.consumer("to-vertx").handler(message -> {
|
||||
eb.publish("chat.to.client", message.body());
|
||||
});
|
||||
|
||||
|
||||
// Serve the non private static pages
|
||||
router.route().handler(StaticHandler.create());
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
package org.bigbluebutton.vertx;
|
||||
|
||||
import io.vertx.core.AbstractVerticle;
|
||||
import io.vertx.ext.web.Router;
|
||||
import io.vertx.ext.web.handler.StaticHandler;
|
||||
import io.vertx.ext.bridge.BridgeEventType;
|
||||
import io.vertx.ext.web.handler.sockjs.BridgeOptions;
|
||||
import io.vertx.ext.web.handler.sockjs.PermittedOptions;
|
||||
import io.vertx.ext.web.handler.sockjs.SockJSHandler;
|
||||
|
||||
public class RealtimeVerticle extends AbstractVerticle {
|
||||
@Override
|
||||
public void start() throws Exception {
|
||||
|
||||
Router router = Router.router(vertx);
|
||||
|
||||
// Allow outbound traffic to the news-feed address
|
||||
|
||||
BridgeOptions options = new BridgeOptions().addOutboundPermitted(new PermittedOptions().setAddress("news-feed"));
|
||||
|
||||
router.route("/eventbus/*").handler(SockJSHandler.create(vertx).bridge(options, event -> {
|
||||
|
||||
// You can also optionally provide a handler like this which will be passed any events that occur on the bridge
|
||||
// You can use this for monitoring or logging, or to change the raw messages in-flight.
|
||||
// It can also be used for fine grained access control.
|
||||
|
||||
if (event.type() == BridgeEventType.SOCKET_CREATED) {
|
||||
System.out.println("A socket was created");
|
||||
}
|
||||
|
||||
// This signals that it's ok to process the event
|
||||
event.complete(true);
|
||||
|
||||
}));
|
||||
|
||||
// Serve the static resources
|
||||
router.route().handler(StaticHandler.create());
|
||||
|
||||
vertx.createHttpServer().requestHandler(router::accept).listen(3000);
|
||||
|
||||
// Publish a message to the address "news-feed" every second
|
||||
vertx.setPeriodic(1000, t -> vertx.eventBus().publish("news-feed", "news from the server!"));
|
||||
}
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
package org.bigbluebutton.vertx;
|
||||
|
||||
import io.vertx.core.AbstractVerticle;
|
||||
import io.vertx.core.http.HttpServerResponse;
|
||||
import io.vertx.core.json.JsonArray;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.ext.web.Router;
|
||||
import io.vertx.ext.web.RoutingContext;
|
||||
import io.vertx.ext.web.handler.BodyHandler;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="http://tfox.org">Tim Fox</a>
|
||||
*/
|
||||
public class SimpleREST extends AbstractVerticle {
|
||||
|
||||
|
||||
private Map<String, JsonObject> products = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
|
||||
setUpInitialData();
|
||||
|
||||
Router router = Router.router(vertx);
|
||||
|
||||
router.route().handler(BodyHandler.create());
|
||||
router.get("/products/:productID").handler(this::handleGetProduct);
|
||||
router.put("/products/:productID").handler(this::handleAddProduct);
|
||||
router.get("/products").handler(this::handleListProducts);
|
||||
|
||||
vertx.createHttpServer().requestHandler(router::accept).listen(4000);
|
||||
}
|
||||
|
||||
private void handleGetProduct(RoutingContext routingContext) {
|
||||
String productID = routingContext.request().getParam("productID");
|
||||
HttpServerResponse response = routingContext.response();
|
||||
if (productID == null) {
|
||||
sendError(400, response);
|
||||
} else {
|
||||
JsonObject product = products.get(productID);
|
||||
if (product == null) {
|
||||
sendError(404, response);
|
||||
} else {
|
||||
response.putHeader("content-type", "application/json").end(product.encodePrettily());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleAddProduct(RoutingContext routingContext) {
|
||||
String productID = routingContext.request().getParam("productID");
|
||||
HttpServerResponse response = routingContext.response();
|
||||
if (productID == null) {
|
||||
sendError(400, response);
|
||||
} else {
|
||||
JsonObject product = routingContext.getBodyAsJson();
|
||||
if (product == null) {
|
||||
sendError(400, response);
|
||||
} else {
|
||||
products.put(productID, product);
|
||||
response.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleListProducts(RoutingContext routingContext) {
|
||||
JsonArray arr = new JsonArray();
|
||||
products.forEach((k, v) -> arr.add(v));
|
||||
routingContext.response().putHeader("content-type", "application/json").end(arr.encodePrettily());
|
||||
}
|
||||
|
||||
private void sendError(int statusCode, HttpServerResponse response) {
|
||||
response.setStatusCode(statusCode).end();
|
||||
}
|
||||
|
||||
private void setUpInitialData() {
|
||||
addProduct(new JsonObject().put("id", "prod3568").put("name", "Egg Whisk").put("price", 3.99).put("weight", 150));
|
||||
addProduct(new JsonObject().put("id", "prod7340").put("name", "Tea Cosy").put("price", 5.99).put("weight", 100));
|
||||
addProduct(new JsonObject().put("id", "prod8643").put("name", "Spatula").put("price", 1.00).put("weight", 80));
|
||||
}
|
||||
|
||||
private void addProduct(JsonObject product) {
|
||||
products.put(product.getString("id"), product);
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
package org.bigbluebutton.vertx;
|
||||
|
||||
import io.vertx.ext.bridge.BridgeEventType;
|
||||
import io.vertx.ext.web.handler.sockjs.BridgeOptions;
|
||||
import io.vertx.ext.web.handler.sockjs.SockJSHandler;
|
||||
|
||||
public class SockJSHandlerFactory {
|
||||
|
||||
public SockJSHandler setupHandler(SockJSHandler ebHandler, BridgeOptions opts) {
|
||||
|
||||
ebHandler.bridge(opts, be -> {
|
||||
if (be.type() == BridgeEventType.SOCKET_CREATED) {
|
||||
System.out.println("Socket create for: " + be.socket().webSession().id());
|
||||
} else if (be.type() == BridgeEventType.SOCKET_CLOSED) {
|
||||
System.out.println("Socket closed for: " + be.socket().webSession().id());
|
||||
} else {
|
||||
System.out.println("Message from: " + be.socket().webSession().id() + " \n " + be.getRawMessage());
|
||||
}
|
||||
be.complete(true);
|
||||
});
|
||||
|
||||
return ebHandler;
|
||||
}
|
||||
}
|
@ -1,125 +0,0 @@
|
||||
package org.bigbluebutton.vertx;
|
||||
|
||||
import io.vertx.core.AbstractVerticle;
|
||||
import io.vertx.core.eventbus.EventBus;
|
||||
import io.vertx.ext.bridge.BridgeEventType;
|
||||
import io.vertx.ext.web.Router;
|
||||
import io.vertx.ext.web.handler.BodyHandler;
|
||||
import io.vertx.ext.web.handler.CookieHandler;
|
||||
import io.vertx.ext.web.handler.SessionHandler;
|
||||
import io.vertx.ext.web.handler.StaticHandler;
|
||||
import io.vertx.ext.web.handler.sockjs.BridgeOptions;
|
||||
import io.vertx.ext.web.handler.sockjs.PermittedOptions;
|
||||
import io.vertx.ext.web.handler.sockjs.SockJSHandler;
|
||||
import io.vertx.ext.web.handler.sockjs.SockJSHandlerOptions;
|
||||
import io.vertx.ext.web.sstore.LocalSessionStore;
|
||||
import org.bigbluebutton.ConnectionManager;
|
||||
|
||||
public class SockJSHandlerVerticle extends AbstractVerticle {
|
||||
private final ConnectionManager gw;
|
||||
|
||||
public SockJSHandlerVerticle(ConnectionManager gw) {
|
||||
this.gw = gw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() throws Exception {
|
||||
|
||||
Router router = Router.router(vertx);
|
||||
|
||||
// We need cookies, sessions and request bodies
|
||||
router.route().handler(CookieHandler.create());
|
||||
router.route().handler(BodyHandler.create());
|
||||
router.route().handler(SessionHandler.create(LocalSessionStore.create(vertx)));
|
||||
|
||||
// Simple auth service which uses a properties file for user/role info
|
||||
//AuthProvider authProvider = new MyAuthProvider(vertx);
|
||||
|
||||
// We need a user session handler too to make sure the user is stored in the session between requests
|
||||
//router.route().handler(UserSessionHandler.create(authProvider));
|
||||
|
||||
// PermittedOptions outboundPermitted2 = new PermittedOptions().setAddressRegex("to-server-.+");
|
||||
// PermittedOptions inboundPermitted2 = new PermittedOptions().setAddressRegex("to-client-.+");
|
||||
|
||||
// Allow events for the designated addresses in/out of the event bus bridge
|
||||
BridgeOptions opts = new BridgeOptions()
|
||||
.addInboundPermitted(new PermittedOptions().setAddress("to-server"))
|
||||
.addOutboundPermitted(new PermittedOptions().setAddressRegex("to-client-.+"));
|
||||
|
||||
SockJSHandlerOptions options = new SockJSHandlerOptions().setHeartbeatInterval(2000);
|
||||
|
||||
// Create the event bus bridge and add it to the router.
|
||||
SockJSHandler sockJSHandler = SockJSHandler.create(vertx, options);
|
||||
|
||||
router.route("/eventbus/*").handler(sockJSHandler);
|
||||
|
||||
EventBus eb = vertx.eventBus();
|
||||
|
||||
sockJSHandler.bridge(opts, be -> {
|
||||
if (be.type() == BridgeEventType.SOCKET_CREATED) {
|
||||
System.out.println("Socket create for session: " + be.socket().webSession().id() + " socketWriteId:" + be.socket().writeHandlerID());
|
||||
eb.consumer(be.socket().webSession().id()).handler(message -> {
|
||||
be.socket().close();
|
||||
});
|
||||
gw.socketCreated(be.socket().webSession().id());
|
||||
} else if (be.type() == BridgeEventType.SOCKET_CLOSED) {
|
||||
System.out.println("Socket closed for: " + be.socket().webSession().id() + " \n " + be.getRawMessage());
|
||||
gw.socketClosed(be.socket().webSession().id());
|
||||
eb.consumer(be.socket().webSession().id()).unregister();
|
||||
} else if (be.type() == BridgeEventType.SOCKET_IDLE) {
|
||||
System.out.println("Socket SOCKET_IDLE for: " + be.socket().webSession().id());
|
||||
} else if (be.type() == BridgeEventType.SOCKET_PING) {
|
||||
System.out.println("Socket SOCKET_PING for: " + be.socket().webSession().id());
|
||||
} else if (be.type() == BridgeEventType.UNREGISTER) {
|
||||
System.out.println("Socket UNREGISTER for: " + be.socket().webSession().id() + " \n " + be.getRawMessage());
|
||||
} else if (be.type() == BridgeEventType.PUBLISH) {
|
||||
System.out.println("Socket PUBLISH for: " + be.socket().webSession().id() + " \n " + be.getRawMessage());
|
||||
} else if (be.type() == BridgeEventType.RECEIVE) {
|
||||
System.out.println("Msg to Client: " + be.socket().webSession().id() + " \n " + be.getRawMessage());
|
||||
} else if (be.type() == BridgeEventType.SEND) {
|
||||
//System.out.println("Msg from Client: " + be.socket().webSession().id() + " \n " + be.getRawMessage());
|
||||
//String body = be.getRawMessage().getJsonObject("body").encode();
|
||||
gw.onMessageReceived(be.socket().webSession().id(), be.getRawMessage().getJsonObject("body"));
|
||||
} else if (be.type() == BridgeEventType.REGISTER) {
|
||||
System.out.println("Socket REGISTER for: " + be.socket().webSession().id() + " \n " + be.getRawMessage());
|
||||
String address = be.getRawMessage().getString("address");
|
||||
gw.register(be.socket().webSession().id(), address);
|
||||
} else {
|
||||
System.out.println("Message from: " + be.socket().webSession().id() + " \n " + be.getRawMessage());
|
||||
}
|
||||
|
||||
|
||||
|
||||
// System.out.println("USER=" + be.socket().webUser().principal());
|
||||
|
||||
be.complete(true);
|
||||
});
|
||||
|
||||
// Create a router endpoint for the static content.
|
||||
router.route().handler(StaticHandler.create());
|
||||
|
||||
// Start the web server and tell it to use the router to handle requests.
|
||||
//vertx.createHttpServer(new HttpServerOptions().setSsl(true).setKeyStoreOptions(
|
||||
// new JksOptions().setPath("server-keystore.jks").setPassword("wibble")
|
||||
// )).requestHandler(router::accept).listen(3001);
|
||||
vertx.createHttpServer().requestHandler(router::accept).listen(3001);
|
||||
|
||||
// Register to listen for messages coming IN to the server
|
||||
eb.consumer("to.server").handler(message -> {
|
||||
// Create a timestamp string
|
||||
// String timestamp = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM).format(Date.from(Instant.now()));
|
||||
// Send the message back out to all clients with the timestamp prepended.
|
||||
//gw.send("TO ECHO:" + timestamp + ": " + message.body());
|
||||
// eb.publish("foofoofoo", message.body());
|
||||
});
|
||||
|
||||
//eb.consumer("to-vertx").handler(message -> {
|
||||
// eb.publish("chat.to.client", message.body());
|
||||
//});
|
||||
|
||||
|
||||
// Serve the non private static pages
|
||||
router.route().handler(StaticHandler.create());
|
||||
}
|
||||
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
package org.bigbluebutton.vertx;
|
||||
|
||||
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.core.eventbus.Message;
|
||||
import io.vertx.core.eventbus.MessageConsumer;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
|
||||
import org.bigbluebutton.VertxToAkkaGateway;
|
||||
|
||||
public class VertxToAkkaBus {
|
||||
|
||||
|
||||
public VertxToAkkaBus(Vertx vertx, VertxToAkkaGateway gw) {
|
||||
|
||||
MessageConsumer<String> consumer =
|
||||
vertx.eventBus().consumer("to-akka-gw");
|
||||
|
||||
consumer.handler(message -> {
|
||||
System.out.println("I have received a message: " + message.body());
|
||||
if (message.replyAddress() != null) {
|
||||
String replyChannel = "reply-channel";
|
||||
MessageConsumer<String> replyConsumer =
|
||||
vertx.eventBus().consumer(replyChannel);
|
||||
replyConsumer.handler(replyMessage -> {
|
||||
System.out.println("Got Authenticated");
|
||||
|
||||
message.reply(replyMessage.body().toString());
|
||||
replyConsumer.unregister();
|
||||
});
|
||||
gw.sendWithReply(message.body().toString(), replyChannel);
|
||||
} else {
|
||||
gw.send(message.body().toString());
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
package org.bigbluebutton
|
||||
|
||||
import io.vertx.core.Vertx
|
||||
import akka.actor._
|
||||
import akka.actor.ActorLogging
|
||||
import org.bigbluebutton.vertx.IAkkaToVertxGateway
|
||||
import org.bigbluebutton.vertx.AkkaToVertxGateway
|
||||
|
||||
object AuthService {
|
||||
def props(gw: AkkaToVertxGateway): Props =
|
||||
Props(classOf[AuthService], gw)
|
||||
}
|
||||
|
||||
class AuthService(gw: AkkaToVertxGateway)
|
||||
extends Actor with ActorLogging {
|
||||
|
||||
def receive = {
|
||||
case msg: String => {
|
||||
println("****** Authenticating " + msg)
|
||||
sender ! "Let `em in!"
|
||||
}
|
||||
case _ => log.error("Cannot handle message ")
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
package org.bigbluebutton
|
||||
|
||||
import akka.actor.ActorSystem
|
||||
import akka.event.Logging
|
||||
import org.bigbluebutton.vertx.HelloWorld
|
||||
import io.vertx.core.Vertx
|
||||
import org.bigbluebutton.client.{ ClientGWApplication, MsgToClientGW }
|
||||
import org.bigbluebutton.client.bus.InternalMessageBus
|
||||
import org.bigbluebutton.vertx.AkkaToVertxGateway
|
||||
import org.bigbluebutton.vertx.VertxToAkkaBus
|
||||
|
||||
object Boot extends App with SystemConfiguration {
|
||||
|
||||
implicit val system = ActorSystem("vertx-akka-system")
|
||||
val log = Logging(system, getClass)
|
||||
|
||||
log.debug("*********** vertx-akka-system ***********************")
|
||||
|
||||
val vertx = Vertx.vertx()
|
||||
|
||||
val vertxGW = new AkkaToVertxGateway(vertx)
|
||||
|
||||
val echoActor = system.actorOf(EchoService.props(vertxGW, vertx), "echo-actor")
|
||||
val authActor = system.actorOf(AuthService.props(vertxGW), "auth-actor")
|
||||
|
||||
val akkaGW = new VertxToAkkaGateway(system, vertx, authActor, echoActor)
|
||||
val vertxToAkkaBus = new VertxToAkkaBus(vertx, akkaGW)
|
||||
val connEventBus = new InternalMessageBus
|
||||
val connectionManager = new ConnectionManager(system, vertx, connEventBus)
|
||||
val clientManager = new ClientManager(system, connEventBus)
|
||||
|
||||
val msgToClientGW = new MsgToClientGW
|
||||
val clientGW = new ClientGWApplication(system, msgToClientGW, connEventBus)
|
||||
|
||||
val hello = new HelloWorld(vertx, akkaGW, connectionManager)
|
||||
hello.startup()
|
||||
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
package org.bigbluebutton
|
||||
|
||||
import akka.actor.{ Actor, ActorLogging, ActorSystem, Props }
|
||||
import org.bigbluebutton.client.bus.{ ConnectionCreated, ConnectionDestroyed, InternalMessageBus }
|
||||
import org.bigbluebutton.client.Client
|
||||
|
||||
class ClientManager(system: ActorSystem, connEventBus: InternalMessageBus) {
|
||||
val actorRef = system.actorOf(ClientManagerActor.props(connEventBus), "clientMgrActor")
|
||||
}
|
||||
|
||||
object ClientManagerActor {
|
||||
val CLIENT_MANAGER_CHANNEL = "client-manager-channel"
|
||||
|
||||
def props(connEventBus: InternalMessageBus): Props = Props(classOf[ClientManagerActor], connEventBus)
|
||||
}
|
||||
|
||||
case class ClientManagerActor(connEventBus: InternalMessageBus) extends Actor with ActorLogging {
|
||||
private var clients = new collection.immutable.HashMap[String, Client]
|
||||
|
||||
def receive = {
|
||||
case m: ConnectionCreated =>
|
||||
val client = Client(m.connInfo.connId, connEventBus)
|
||||
clients += client.clientId -> client
|
||||
client.actorRef forward (m)
|
||||
case m: ConnectionDestroyed =>
|
||||
val client = clients.get(m.connInfo.connId)
|
||||
client foreach { u =>
|
||||
clients -= m.connInfo.connId
|
||||
u.actorRef forward (m)
|
||||
}
|
||||
|
||||
case _ => log.debug("***** Connection cannot handle msg ")
|
||||
}
|
||||
|
||||
override def preStart(): Unit = {
|
||||
super.preStart()
|
||||
connEventBus.subscribe(self, ClientManagerActor.CLIENT_MANAGER_CHANNEL)
|
||||
}
|
||||
|
||||
override def postStop(): Unit = {
|
||||
connEventBus.unsubscribe(self, ClientManagerActor.CLIENT_MANAGER_CHANNEL)
|
||||
super.postStop()
|
||||
}
|
||||
}
|
@ -1,124 +0,0 @@
|
||||
package org.bigbluebutton
|
||||
|
||||
import akka.actor.{ Actor, ActorContext, ActorLogging, ActorRef, Props }
|
||||
import io.vertx.core.{ Handler, Vertx }
|
||||
import io.vertx.core.eventbus.{ Message, MessageConsumer }
|
||||
import io.vertx.core.json.JsonObject
|
||||
import org.bigbluebutton.client.bus.ConnInfo2
|
||||
import org.bigbluebutton.client.bus._
|
||||
|
||||
object Connection {
|
||||
def apply(connId: String, vertx: Vertx, connEventBus: InternalMessageBus)(implicit context: ActorContext): Connection = new Connection(connId, vertx, connEventBus)(context)
|
||||
}
|
||||
|
||||
class Connection(val connId: String, vertx: Vertx, connEventBus: InternalMessageBus)(implicit val context: ActorContext) {
|
||||
val actorRef = context.actorOf(ConnectionActor.props(connId, vertx, connEventBus), "connActor" + "-" + connId)
|
||||
|
||||
val consumer: MessageConsumer[JsonObject] = vertx.eventBus().consumer("from-socket-" + connId)
|
||||
consumer.handler(new MyConnHandler(actorRef))
|
||||
}
|
||||
|
||||
object ConnectionActor {
|
||||
def props(connId: String, vertx: Vertx, connEventBus: InternalMessageBus): Props = Props(classOf[ConnectionActor], connId, vertx, connEventBus)
|
||||
}
|
||||
|
||||
case class MsgFoo(msg: JsonObject)
|
||||
|
||||
class ConnectionActor(connId: String, vertx: Vertx, connEventBus: InternalMessageBus) extends Actor with ActorLogging {
|
||||
|
||||
var handshakeDone = false
|
||||
var connInfo: Option[ConnInfo2] = None
|
||||
var clientAddress: Option[String] = None
|
||||
|
||||
def receive = {
|
||||
case m: SocketDestroyed =>
|
||||
connInfo foreach { conn =>
|
||||
connEventBus.publish(MsgFromConnBusMsg(ClientManagerActor.CLIENT_MANAGER_CHANNEL, ConnectionDestroyed(conn)))
|
||||
}
|
||||
|
||||
context stop self
|
||||
case m: SocketRegister =>
|
||||
clientAddress = Some(m.channel)
|
||||
|
||||
case m: MsgFoo =>
|
||||
if (!handshakeDone) {
|
||||
for {
|
||||
conn <- getConnInfo(m.msg)
|
||||
} yield {
|
||||
println("**************************** HANDSHAKE DONE *****************************")
|
||||
handshakeDone = true
|
||||
connInfo = Some(conn)
|
||||
connEventBus.publish(MsgFromConnBusMsg(ClientManagerActor.CLIENT_MANAGER_CHANNEL, ConnectionCreated(conn)))
|
||||
|
||||
val response = buildHandshakeReply(conn.meetingId, conn.userId, conn.token)
|
||||
vertx.eventBus().publish("to-client-" + conn.token, response)
|
||||
}
|
||||
} else {
|
||||
//println("************ FORWARDING TO CLIENT ACTOR *****************************")
|
||||
connInfo foreach { conn =>
|
||||
//println("************ FORWARDING TO CLIENT ACTOR " + "clientActor-" + conn.connId + " *****************************")
|
||||
connEventBus.publish(MsgFromConnBusMsg("clientActor-" + conn.connId, MsgFromConnMsg(conn, m.msg.encode())))
|
||||
}
|
||||
}
|
||||
|
||||
case m: MsgToConnMsg =>
|
||||
//println("MsgToConnMsg " + m.json)
|
||||
connInfo foreach { conn =>
|
||||
val jsonObject = new JsonObject(m.json)
|
||||
vertx.eventBus().publish("to-client-" + conn.token, jsonObject)
|
||||
}
|
||||
|
||||
case _ => log.debug("***** Connection cannot handle msg ")
|
||||
}
|
||||
|
||||
private def getConnInfo(msg: JsonObject): Option[ConnInfo2] = {
|
||||
var conn: Option[ConnInfo2] = None
|
||||
|
||||
if (msg.containsKey("header") && msg.containsKey("body")) {
|
||||
val header = msg.getJsonObject("header")
|
||||
val body = msg.getJsonObject("body")
|
||||
if (header.containsKey("name") && header.containsKey("meetingId")
|
||||
&& header.containsKey("userId") && body.containsKey("token")) {
|
||||
val meetingId = header.getString("meetingId")
|
||||
val userId = header.getString("userId")
|
||||
val token = body.getString("token")
|
||||
conn = Some(new ConnInfo2(meetingId, userId, token, connId))
|
||||
}
|
||||
}
|
||||
|
||||
conn
|
||||
}
|
||||
|
||||
private def buildHandshakeReply(meetingId: String, userId: String, token: String): JsonObject = {
|
||||
val header: JsonObject = new JsonObject()
|
||||
header.put("name", "HandshakeReplyMessage")
|
||||
header.put("userId", userId)
|
||||
header.put("meetingId", meetingId)
|
||||
|
||||
val body = new JsonObject()
|
||||
body.put("token", token)
|
||||
|
||||
val reply = new JsonObject()
|
||||
reply.put("header", header)
|
||||
reply.put("body", body)
|
||||
|
||||
reply
|
||||
}
|
||||
|
||||
override def preStart(): Unit = {
|
||||
super.preStart()
|
||||
connEventBus.subscribe(self, "connActor-" + connId)
|
||||
}
|
||||
|
||||
override def postStop(): Unit = {
|
||||
super.postStop()
|
||||
connEventBus.unsubscribe(self, "connActor-" + connId)
|
||||
}
|
||||
}
|
||||
|
||||
class MyConnHandler(actorRef: ActorRef) extends Handler[Message[JsonObject]] {
|
||||
def handle(message: Message[JsonObject]) = {
|
||||
//println("My Handler " + message.body())
|
||||
actorRef ! (MsgFoo(message.body()))
|
||||
}
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
package org.bigbluebutton
|
||||
|
||||
import akka.actor.{ Actor, ActorContext, ActorLogging, ActorSystem, Props }
|
||||
import io.vertx.core.Vertx
|
||||
import io.vertx.core.json.JsonObject
|
||||
import org.bigbluebutton.client.bus.InternalMessageBus
|
||||
|
||||
class ConnectionManager(system: ActorSystem, vertx: Vertx, connEventBus: InternalMessageBus) {
|
||||
val actorRef = system.actorOf(ConnManagerActor.props(vertx, connEventBus), "connMgrActor")
|
||||
|
||||
def socketCreated(id: String): Unit = {
|
||||
actorRef ! SocketCreated(id)
|
||||
}
|
||||
|
||||
def socketClosed(id: String): Unit = {
|
||||
actorRef ! SocketDestroyed(id)
|
||||
}
|
||||
|
||||
def register(id: String, address: String): Unit = {
|
||||
actorRef ! SocketRegister(id, address)
|
||||
}
|
||||
|
||||
def onMessageReceived(id: String, msg: JsonObject): Unit = {
|
||||
vertx.eventBus().publish("from-socket-" + id, msg)
|
||||
}
|
||||
}
|
||||
|
||||
case class SocketCreated(id: String)
|
||||
case class SocketDestroyed(id: String)
|
||||
case class SocketRegister(id: String, channel: String)
|
||||
|
||||
object ConnManagerActor {
|
||||
def props(vertx: Vertx, connEventBus: InternalMessageBus): Props = Props(classOf[ConnManagerActor], vertx, connEventBus)
|
||||
}
|
||||
|
||||
case class ConnManagerActor(vertx: Vertx, connEventBus: InternalMessageBus) extends Actor with ActorLogging {
|
||||
private var conns = new collection.immutable.HashMap[String, Connection]
|
||||
|
||||
def receive = {
|
||||
case m: SocketCreated =>
|
||||
val conn = Connection(m.id, vertx, connEventBus)
|
||||
conns += conn.connId -> conn
|
||||
case m: SocketDestroyed =>
|
||||
val conn = conns.get(m.id)
|
||||
conn foreach { u =>
|
||||
conns -= m.id
|
||||
u.actorRef forward (m)
|
||||
}
|
||||
case m: SocketRegister =>
|
||||
val conn = conns.get(m.id)
|
||||
conn foreach (u => u.actorRef forward (m))
|
||||
|
||||
case _ => log.debug("***** Connection cannot handle msg ")
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
package org.bigbluebutton
|
||||
|
||||
import io.vertx.core.Vertx
|
||||
import akka.actor._
|
||||
import akka.actor.ActorLogging
|
||||
import org.bigbluebutton.vertx.IAkkaToVertxGateway
|
||||
import org.bigbluebutton.vertx.AkkaToVertxGateway
|
||||
|
||||
object EchoService {
|
||||
def props(gw: AkkaToVertxGateway, vertx: Vertx): Props =
|
||||
Props(classOf[EchoService], gw, vertx)
|
||||
}
|
||||
|
||||
class EchoService(gw: AkkaToVertxGateway, vertx: Vertx) extends Actor with ActorLogging {
|
||||
|
||||
private var i: Int = 0;
|
||||
|
||||
def receive = {
|
||||
case msg: String => {
|
||||
//println("****** Echoing " + msg)
|
||||
gw.send("FROM ECHO: " + msg)
|
||||
i += 1
|
||||
if (i > 50) {
|
||||
//gw.send("CLOSE_SOCKET")
|
||||
vertx.eventBus.publish("to-vertx", "CLOSE_SOCKET")
|
||||
}
|
||||
}
|
||||
case _ => log.error("Cannot handle message ")
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
package org.bigbluebutton
|
||||
|
||||
import io.vertx.ext.web.handler.{ BodyHandler, CookieHandler, SessionHandler }
|
||||
import io.vertx.ext.web.sstore.LocalSessionStore
|
||||
import io.vertx.lang.scala.ScalaVerticle
|
||||
import io.vertx.scala.ext.web.Router
|
||||
|
||||
class SockJSHandlerVerticle extends ScalaVerticle {
|
||||
|
||||
override def start(): Unit = {
|
||||
println("Starting")
|
||||
//val router = Router.router(vertx)
|
||||
|
||||
// We need cookies, sessions and request bodies
|
||||
//router.route().handler(CookieHandler.create)
|
||||
//router.route().handler(BodyHandler.create)
|
||||
//router.route().handler(SessionHandler.create(LocalSessionStore.create(vertx)))
|
||||
|
||||
// Simple auth service which uses a properties file for user/role info
|
||||
//AuthProvider authProvider = new MyAuthProvider(vertx);
|
||||
|
||||
// We need a user session handler too to make sure the user is stored in the session between requests
|
||||
//router.route().handler(UserSessionHandler.create(authProvider));
|
||||
|
||||
// Handles the actual login
|
||||
//router.route("/loginhandler").handler(FormLoginHandler.create(authProvider));
|
||||
}
|
||||
|
||||
override def stop(): Unit = {
|
||||
println("Stopping")
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
package org.bigbluebutton
|
||||
|
||||
import com.typesafe.config.ConfigFactory
|
||||
import scala.util.Try
|
||||
|
||||
trait SystemConfiguration {
|
||||
|
||||
val config = ConfigFactory.load()
|
||||
|
||||
lazy val redisHost = Try(config.getString("redis.host")).getOrElse("127.0.0.1")
|
||||
lazy val redisPort = Try(config.getInt("redis.port")).getOrElse(6379)
|
||||
lazy val redisPassword = Try(config.getString("redis.password")).getOrElse("")
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
package org.bigbluebutton
|
||||
|
||||
import org.bigbluebutton.vertx.IAkkaToVertxGateway
|
||||
import akka.pattern.{ ask, pipe }
|
||||
import akka.util.Timeout
|
||||
import scala.concurrent.duration._
|
||||
import scala.util.Success
|
||||
import scala.util.Failure
|
||||
import akka.actor.ActorRef
|
||||
import io.vertx.core.Vertx
|
||||
import io.vertx.core.eventbus.MessageConsumer
|
||||
import io.vertx.core.Handler
|
||||
import io.vertx.core.eventbus.Message
|
||||
import akka.actor.ActorSystem
|
||||
|
||||
class VertxToAkkaGateway(system: ActorSystem, vertx: Vertx,
|
||||
authService: ActorRef,
|
||||
echoService: ActorRef) extends IAkkaToVertxGateway {
|
||||
implicit def executionContext = system.dispatcher
|
||||
|
||||
val consumer: MessageConsumer[String] = vertx.eventBus().consumer("foofoofoo")
|
||||
|
||||
def handle(m: Message[String]) = println(m.body())
|
||||
|
||||
consumer.handler(new MyHandler())
|
||||
|
||||
def sendWithReply(json: String, replyChannel: String) {
|
||||
val future = authService.ask(json)(5 seconds)
|
||||
|
||||
future onComplete {
|
||||
case Success(result) => {
|
||||
vertx.eventBus().send("reply-channel", "You can come in.")
|
||||
}
|
||||
case Failure(failure) => {
|
||||
vertx.eventBus().send("reply-channel", "You can NOT come in.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def send(json: String) {
|
||||
echoService ! json
|
||||
}
|
||||
}
|
||||
|
||||
class MyHandler extends Handler[Message[String]] {
|
||||
def handle(message: Message[String]) = {
|
||||
println("My Handler " + message.body())
|
||||
}
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
package org.bigbluebutton.client
|
||||
|
||||
import akka.actor.{ Actor, ActorContext, ActorLogging, Props }
|
||||
import org.bigbluebutton.client.bus._
|
||||
import org.bigbluebutton.client.meeting.Connections
|
||||
|
||||
object Client {
|
||||
def apply(clientId: String, connEventBus: InternalMessageBus)(implicit context: ActorContext): Client = new Client(clientId, connEventBus)(context)
|
||||
}
|
||||
|
||||
class Client(val clientId: String, connEventBus: InternalMessageBus)(implicit val context: ActorContext) {
|
||||
val actorRef = context.actorOf(ClientActor.props(clientId, connEventBus), "clientActor" + "-" + clientId)
|
||||
}
|
||||
|
||||
object ClientActor {
|
||||
def props(clientId: String, connEventBus: InternalMessageBus): Props = Props(classOf[ClientActor], clientId, connEventBus)
|
||||
}
|
||||
|
||||
class ClientActor(clientId: String, connEventBus: InternalMessageBus)
|
||||
extends Actor with ActorLogging with SystemConfiguration {
|
||||
|
||||
private val conns = new Connections
|
||||
private var authorized = false
|
||||
|
||||
def receive = {
|
||||
case m: ConnectionCreated =>
|
||||
connEventBus.publish(MsgFromConnBusMsg(fromClientChannel, ClientConnectedMsg(m.connInfo)))
|
||||
case m: ConnectionDestroyed =>
|
||||
connEventBus.publish(MsgFromConnBusMsg(fromClientChannel, ClientDisconnectedMsg(m.connInfo)))
|
||||
context stop self
|
||||
case m: MsgFromConnMsg =>
|
||||
connEventBus.publish(MsgFromConnBusMsg(fromClientChannel, MsgFromClientMsg(m.connInfo, m.json)))
|
||||
case m: DirectMsgToClient =>
|
||||
connEventBus.publish(MsgFromConnBusMsg("connActor-" + clientId, MsgToConnMsg(m.data.core.toString())))
|
||||
case _ => log.debug("***** ClientActor cannot handle msg ")
|
||||
}
|
||||
|
||||
override def preStart(): Unit = {
|
||||
super.preStart()
|
||||
//println("******** CLIENT ACTOR CREATED " + "clientActor-" + clientId + " *****************************")
|
||||
connEventBus.subscribe(self, "clientActor-" + clientId)
|
||||
|
||||
}
|
||||
|
||||
override def postStop(): Unit = {
|
||||
connEventBus.unsubscribe(self, "clientActor-" + clientId)
|
||||
super.postStop()
|
||||
}
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
package org.bigbluebutton.client
|
||||
|
||||
import akka.actor.ActorSystem
|
||||
import akka.event.Logging
|
||||
import org.bigbluebutton.client.bus._
|
||||
import org.bigbluebutton.client.endpoint.redis.{ AppsRedisSubscriberActor, MessageSender, RedisPublisher }
|
||||
import org.bigbluebutton.client.meeting.MeetingManagerActor
|
||||
import scala.concurrent.duration._
|
||||
|
||||
class ClientGWApplication(system: ActorSystem, val msgToClientGW: MsgToClientGW, connEventBus: InternalMessageBus) extends SystemConfiguration {
|
||||
|
||||
implicit val timeout = akka.util.Timeout(3 seconds)
|
||||
|
||||
private val redisPublisher = new RedisPublisher(system)
|
||||
private val msgSender: MessageSender = new MessageSender(redisPublisher)
|
||||
|
||||
private val messageSenderActorRef = system.actorOf(MessageSenderActor.props(msgSender), "messageSenderActor")
|
||||
|
||||
connEventBus.subscribe(messageSenderActorRef, toAkkaAppsJsonChannel)
|
||||
|
||||
private val meetingManagerActorRef = system.actorOf(MeetingManagerActor.props(connEventBus), "meetingManagerActor")
|
||||
connEventBus.subscribe(meetingManagerActorRef, fromAkkaAppsChannel)
|
||||
connEventBus.subscribe(meetingManagerActorRef, fromClientChannel)
|
||||
|
||||
private val msgToAkkaAppsToJsonActor = system.actorOf(MsgToAkkaAppsToJsonActor.props(connEventBus), "msgToAkkaAppsToJsonActor")
|
||||
|
||||
connEventBus.subscribe(msgToAkkaAppsToJsonActor, toAkkaAppsChannel)
|
||||
|
||||
private val msgToClientJsonActor = system.actorOf(MsgToClientJsonActor.props(msgToClientGW), "msgToClientJsonActor")
|
||||
|
||||
//connEventBus.subscribe(msgToClientJsonActor, toClientChannel)
|
||||
|
||||
private val appsRedisSubscriberActor = system.actorOf(AppsRedisSubscriberActor.props(connEventBus), "appsRedisSubscriberActor")
|
||||
|
||||
private val receivedJsonMsgHdlrActor = system.actorOf(ReceivedJsonMsgHdlrActor.props(connEventBus), "receivedJsonMsgHdlrActor")
|
||||
|
||||
connEventBus.subscribe(receivedJsonMsgHdlrActor, fromAkkaAppsJsonChannel)
|
||||
|
||||
/**
|
||||
*
|
||||
* External Interface for Gateway
|
||||
*/
|
||||
|
||||
def connect(connInfo: ConnInfo2): Unit = {
|
||||
//log.debug("**** ClientGWApplication connect " + connInfo)
|
||||
connEventBus.publish(MsgFromConnBusMsg(fromClientChannel, new ClientConnectedMsg(connInfo)))
|
||||
}
|
||||
|
||||
def disconnect(connInfo: ConnInfo2): Unit = {
|
||||
//log.debug("**** ClientGWApplication disconnect " + connInfo)
|
||||
connEventBus.publish(MsgFromConnBusMsg(fromClientChannel, new ClientDisconnectedMsg(connInfo)))
|
||||
}
|
||||
|
||||
def handleMsgFromClient(connInfo: ConnInfo2, json: String): Unit = {
|
||||
//log.debug("**** ClientGWApplication handleMsgFromClient " + json)
|
||||
connEventBus.publish(MsgFromConnBusMsg(fromClientChannel, new MsgFromClientMsg(connInfo, json)))
|
||||
}
|
||||
|
||||
def send(channel: String, json: String): Unit = {
|
||||
//log.debug("Sending message {}", json)
|
||||
connEventBus.publish(MsgFromConnBusMsg(toAkkaAppsJsonChannel, new JsonMsgToAkkaApps(channel, json)))
|
||||
}
|
||||
|
||||
def shutdown(): Unit = {
|
||||
system.terminate()
|
||||
}
|
||||
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
package org.bigbluebutton.client
|
||||
|
||||
import org.bigbluebutton.client.bus.ConnInfo2
|
||||
|
||||
class ClientInGW(val clientGWApp: ClientGWApplication) extends IClientInGW {
|
||||
|
||||
def connect(connInfo: ConnInfo2): Unit = {
|
||||
clientGWApp.connect(connInfo)
|
||||
}
|
||||
|
||||
def disconnect(connInfo: ConnInfo2): Unit = {
|
||||
clientGWApp.disconnect(connInfo)
|
||||
}
|
||||
|
||||
def handleMsgFromClient(connInfo: ConnInfo2, json: String): Unit = {
|
||||
clientGWApp.handleMsgFromClient(connInfo, json)
|
||||
}
|
||||
|
||||
def send(channel: String, json: String): Unit = {
|
||||
clientGWApp.send(channel, json)
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
package org.bigbluebutton.client
|
||||
|
||||
import java.io.{ PrintWriter, StringWriter }
|
||||
|
||||
import scala.concurrent.duration._
|
||||
import akka.actor.{ Actor, ActorLogging, OneForOneStrategy, Props }
|
||||
import akka.actor.SupervisorStrategy.Resume
|
||||
import org.bigbluebutton.client.bus.JsonMsgToAkkaApps
|
||||
import org.bigbluebutton.client.endpoint.redis.MessageSender
|
||||
|
||||
object MessageSenderActor {
|
||||
def props(msgSender: MessageSender): Props = Props(classOf[MessageSenderActor], msgSender)
|
||||
}
|
||||
|
||||
class MessageSenderActor(msgSender: MessageSender) extends Actor with ActorLogging {
|
||||
|
||||
override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) {
|
||||
case e: Exception => {
|
||||
val sw: StringWriter = new StringWriter()
|
||||
sw.write("An exception has been thrown on MessageSenderActor, exception message [" + e.getMessage() + "] (full stacktrace below)\n")
|
||||
e.printStackTrace(new PrintWriter(sw))
|
||||
log.error(sw.toString())
|
||||
Resume
|
||||
}
|
||||
}
|
||||
|
||||
def receive = {
|
||||
case msg: JsonMsgToAkkaApps => msgSender.send(msg.channel, msg.json)
|
||||
}
|
||||
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
package org.bigbluebutton.client
|
||||
|
||||
import akka.actor.{ Actor, ActorLogging, Props }
|
||||
import org.bigbluebutton.client.bus._
|
||||
import org.bigbluebutton.common2.msgs.BbbCommonEnvJsNodeMsg
|
||||
import org.bigbluebutton.common2.util.JsonUtil
|
||||
|
||||
object MsgToAkkaAppsToJsonActor {
|
||||
def props(connEventBus: InternalMessageBus): Props =
|
||||
Props(classOf[MsgToAkkaAppsToJsonActor], connEventBus)
|
||||
|
||||
}
|
||||
class MsgToAkkaAppsToJsonActor(connEventBus: InternalMessageBus)
|
||||
extends Actor with ActorLogging with SystemConfiguration {
|
||||
|
||||
def receive = {
|
||||
case msg: MsgToAkkaApps => handle(msg)
|
||||
}
|
||||
|
||||
def handle(msg: MsgToAkkaApps): Unit = {
|
||||
println("**************** TO AKKA APPS MESSAGE ***************")
|
||||
val json = JsonUtil.toJson(msg.payload)
|
||||
val jsonMsg = JsonMsgToAkkaApps(toAkkaAppsRedisChannel, json)
|
||||
connEventBus.publish(MsgFromConnBusMsg(toAkkaAppsJsonChannel, jsonMsg))
|
||||
}
|
||||
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
package org.bigbluebutton.client
|
||||
|
||||
import org.bigbluebutton.red5.client.messaging.{ BroadcastToMeetingMsg, DirectToClientMsg, ClientMessage, IConnectionInvokerService }
|
||||
|
||||
sealed trait SystemMessage
|
||||
case class DisconnectConnection(connId: String) extends SystemMessage
|
||||
case class DisconnectAllConnections(scope: String) extends SystemMessage
|
||||
|
||||
class MsgToClientGW() {
|
||||
|
||||
def broadcastToMeeting(msg: BroadcastToMeetingMsg): Unit = {
|
||||
//connInvokerService.sendMessage(msg)
|
||||
}
|
||||
|
||||
def directToClient(msg: DirectToClientMsg): Unit = {
|
||||
//connInvokerService.sendMessage(msg)
|
||||
}
|
||||
|
||||
def systemMessage(msg: ClientMessage): Unit = {
|
||||
//connInvokerService.sendMessage(msg)
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
package org.bigbluebutton.client
|
||||
|
||||
import akka.actor.{ Actor, ActorLogging, Props }
|
||||
import org.bigbluebutton.client.bus._
|
||||
import org.bigbluebutton.common2.util.JsonUtil
|
||||
import org.bigbluebutton.red5.client.messaging._
|
||||
|
||||
object MsgToClientJsonActor {
|
||||
def props(msgToClientGW: MsgToClientGW): Props =
|
||||
Props(classOf[MsgToClientJsonActor], msgToClientGW)
|
||||
}
|
||||
|
||||
class MsgToClientJsonActor(msgToClientGW: MsgToClientGW) extends Actor with ActorLogging {
|
||||
|
||||
def receive = {
|
||||
case msg: BroadcastMsgToMeeting => handleBroadcastMsg(msg)
|
||||
case msg: DirectMsgToClient => handleDirectMsg(msg)
|
||||
case msg: DisconnectClientMsg => handleDisconnectClientMsg(msg)
|
||||
case msg: DisconnectAllMeetingClientsMsg => handleDisconnectAllMeetingClientsMsg(msg)
|
||||
}
|
||||
|
||||
def handleBroadcastMsg(msg: BroadcastMsgToMeeting): Unit = {
|
||||
val meetingId = msg.meetingId
|
||||
val msgName = msg.data.envelope.name
|
||||
val json = JsonUtil.toJson(msg.data.core)
|
||||
|
||||
val broadcast = new BroadcastToMeetingMsg(meetingId, msgName, json)
|
||||
msgToClientGW.broadcastToMeeting(broadcast)
|
||||
}
|
||||
|
||||
def handleDirectMsg(msg: DirectMsgToClient): Unit = {
|
||||
val meetingId = msg.meetingId
|
||||
val connId = msg.connId
|
||||
val msgName = msg.data.envelope.name
|
||||
val json = JsonUtil.toJson(msg.data.core)
|
||||
|
||||
val direct = new DirectToClientMsg(meetingId, connId, msgName, json)
|
||||
msgToClientGW.directToClient(direct)
|
||||
}
|
||||
|
||||
def handleDisconnectClientMsg(msg: DisconnectClientMsg): Unit = {
|
||||
val meetingId = msg.meetingId
|
||||
val connId = msg.connId
|
||||
|
||||
msgToClientGW.systemMessage(new CloseConnectionMsg(meetingId, connId))
|
||||
}
|
||||
|
||||
def handleDisconnectAllMeetingClientsMsg(msg: DisconnectAllMeetingClientsMsg): Unit = {
|
||||
val meetingId = msg.meetingId
|
||||
|
||||
msgToClientGW.systemMessage(new CloseMeetingAllConnectionsMsg(meetingId))
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
package org.bigbluebutton.client
|
||||
|
||||
import akka.actor.{ Actor, ActorLogging, Props }
|
||||
import org.bigbluebutton.client.bus.{ InternalMessageBus, JsonMsgFromAkkaApps, MsgFromAkkaApps, MsgFromConnBusMsg }
|
||||
import org.bigbluebutton.common2.msgs.BbbCommonEnvJsNodeMsg
|
||||
import org.bigbluebutton.common2.util.JsonUtil
|
||||
|
||||
import scala.util.{ Failure, Success }
|
||||
|
||||
object ReceivedJsonMsgHdlrActor {
|
||||
def props(connEventBus: InternalMessageBus): Props =
|
||||
Props(classOf[ReceivedJsonMsgHdlrActor], connEventBus)
|
||||
}
|
||||
|
||||
class ReceivedJsonMsgHdlrActor(val connEventBus: InternalMessageBus)
|
||||
extends Actor with ActorLogging with SystemConfiguration {
|
||||
|
||||
def receive = {
|
||||
case msg: JsonMsgFromAkkaApps => handleReceivedJsonMessage(msg)
|
||||
|
||||
case _ => // do nothing
|
||||
}
|
||||
|
||||
def handleReceivedJsonMessage(msg: JsonMsgFromAkkaApps): Unit = {
|
||||
//log.debug("****** Received JSON msg " + msg.data)
|
||||
JsonUtil.fromJson[BbbCommonEnvJsNodeMsg](msg.data) match {
|
||||
case Success(m) => connEventBus.publish(MsgFromConnBusMsg(fromAkkaAppsChannel, MsgFromAkkaApps(m)))
|
||||
case Failure(ex) => log.error("Failed to deserialize message " + ex)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
package org.bigbluebutton.client
|
||||
|
||||
import scala.util.Try
|
||||
import com.typesafe.config.ConfigFactory
|
||||
|
||||
trait SystemConfiguration {
|
||||
val config = ConfigFactory.load()
|
||||
|
||||
lazy val redisHost = Try(config.getString("redis.host")).getOrElse("127.0.0.1")
|
||||
lazy val redisPort = Try(config.getInt("redis.port")).getOrElse(6379)
|
||||
lazy val redisPassword = Try(config.getString("redis.password")).getOrElse("")
|
||||
|
||||
lazy val toAkkaAppsRedisChannel = Try(config.getString("redis.toAkkaAppsRedisChannel")).getOrElse("to-akka-apps-redis-channel")
|
||||
lazy val fromAkkaAppsRedisChannel = Try(config.getString("redis.fromAkkaAppsRedisChannel")).getOrElse("from-akka-apps-redis-channel")
|
||||
lazy val meetingManagerChannel = Try(config.getString("eventBus.meetingManagerChannel")).getOrElse("FOOOOOOOOO")
|
||||
lazy val fromAkkaAppsChannel = Try(config.getString("eventBus.fromAkkaAppsChannel")).getOrElse("from-akka-apps-channel")
|
||||
lazy val toAkkaAppsChannel = Try(config.getString("eventBus.toAkkaAppsChannel")).getOrElse("to-akka-apps-channel")
|
||||
lazy val fromClientChannel = Try(config.getString("eventBus.fromClientChannel")).getOrElse("from-client-channel")
|
||||
//lazy val toClientChannel = Try(config.getString("eventBus.toClientChannel")).getOrElse("to-client-channel")
|
||||
lazy val toAkkaAppsJsonChannel = Try(config.getString("eventBus.toAkkaAppsChannel")).getOrElse("to-akka-apps-json-channel")
|
||||
lazy val fromAkkaAppsJsonChannel = Try(config.getString("eventBus.fromAkkaAppsChannel")).getOrElse("from-akka-apps-json-channel")
|
||||
|
||||
lazy val fromAkkaAppsWbRedisChannel = Try(config.getString("redis.fromAkkaAppsWbRedisChannel")).getOrElse("from-akka-apps-wb-redis-channel")
|
||||
lazy val fromAkkaAppsChatRedisChannel = Try(config.getString("redis.fromAkkaAppsChatRedisChannel")).getOrElse("from-akka-apps-chat-redis-channel")
|
||||
lazy val fromAkkaAppsPresRedisChannel = Try(config.getString("redis.fromAkkaAppsPresRedisChannel")).getOrElse("from-akka-apps-pres-redis-channel")
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
package org.bigbluebutton.client.bus
|
||||
|
||||
import akka.actor.ActorRef
|
||||
import akka.event.{ EventBus, LookupClassification }
|
||||
import org.bigbluebutton.client.bus.ConnInfo2
|
||||
import org.bigbluebutton.common2.msgs.BbbCommonEnvJsNodeMsg
|
||||
|
||||
case class ConnInfo2(meetingId: String, userId: String, token: String, connId: String)
|
||||
|
||||
sealed trait FromConnMsg
|
||||
case class ConnectionCreated(connInfo: ConnInfo2) extends FromConnMsg
|
||||
case class ConnectionDestroyed(connInfo: ConnInfo2) extends FromConnMsg
|
||||
case class MsgToConnMsg(json: String) extends FromConnMsg
|
||||
case class MsgFromConnMsg(connInfo: ConnInfo2, json: String) extends FromConnMsg
|
||||
case class JsonMsgFromAkkaApps(name: String, data: String) extends FromConnMsg
|
||||
case class JsonMsgToAkkaApps(channel: String, json: String) extends FromConnMsg
|
||||
case class MsgFromAkkaApps(payload: BbbCommonEnvJsNodeMsg) extends FromConnMsg
|
||||
case class MsgToAkkaApps(payload: BbbCommonEnvJsNodeMsg) extends FromConnMsg
|
||||
case class BroadcastMsgToMeeting(meetingId: String, data: BbbCommonEnvJsNodeMsg) extends FromConnMsg
|
||||
case class DirectMsgToClient(meetingId: String, connId: String, data: BbbCommonEnvJsNodeMsg) extends FromConnMsg
|
||||
case class DisconnectClientMsg(meetingId: String, connId: String) extends FromConnMsg
|
||||
case class DisconnectAllMeetingClientsMsg(meetingId: String) extends FromConnMsg
|
||||
case class ClientConnectedMsg(connInfo: ConnInfo2) extends FromConnMsg
|
||||
case class ClientDisconnectedMsg(connInfo: ConnInfo2) extends FromConnMsg
|
||||
case class MsgFromClientMsg(connInfo: ConnInfo2, json: String) extends FromConnMsg
|
||||
|
||||
case class MsgFromConnBusMsg(val topic: String, val payload: FromConnMsg)
|
||||
|
||||
class InternalMessageBus extends EventBus with LookupClassification {
|
||||
type Event = MsgFromConnBusMsg
|
||||
type Classifier = String
|
||||
type Subscriber = ActorRef
|
||||
|
||||
// is used for extracting the classifier from the incoming events
|
||||
override protected def classify(event: Event): Classifier = event.topic
|
||||
|
||||
// will be invoked for each event for all subscribers which registered themselves
|
||||
// for the event’s classifier
|
||||
override protected def publish(event: Event, subscriber: Subscriber): Unit = {
|
||||
subscriber ! event.payload
|
||||
}
|
||||
|
||||
// must define a full order over the subscribers, expressed as expected from
|
||||
// `java.lang.Comparable.compare`
|
||||
override protected def compareSubscribers(a: Subscriber, b: Subscriber): Int =
|
||||
a.compareTo(b)
|
||||
|
||||
// determines the initial size of the index data structure
|
||||
// used internally (i.e. the expected number of different classifiers)
|
||||
override protected def mapSize: Int = 128
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
package org.bigbluebutton.client.endpoint.redis
|
||||
|
||||
import akka.actor.{ ActorLogging, OneForOneStrategy, Props }
|
||||
import akka.actor.SupervisorStrategy.Resume
|
||||
import java.io.{ PrintWriter, StringWriter }
|
||||
import java.net.InetSocketAddress
|
||||
|
||||
import redis.actors.RedisSubscriberActor
|
||||
import redis.api.pubsub.{ Message, PMessage }
|
||||
|
||||
import scala.concurrent.duration._
|
||||
import org.bigbluebutton.client._
|
||||
import org.bigbluebutton.client.bus._
|
||||
import redis.api.servers.ClientSetname
|
||||
|
||||
object AppsRedisSubscriberActor extends SystemConfiguration {
|
||||
|
||||
val channels = Seq(fromAkkaAppsRedisChannel, fromAkkaAppsWbRedisChannel, fromAkkaAppsChatRedisChannel, fromAkkaAppsPresRedisChannel)
|
||||
val patterns = Seq("bigbluebutton:from-bbb-apps:*")
|
||||
|
||||
def props(connEventBus: InternalMessageBus): Props =
|
||||
Props(classOf[AppsRedisSubscriberActor], connEventBus,
|
||||
redisHost, redisPort,
|
||||
channels, patterns).withDispatcher("akka.rediscala-subscriber-worker-dispatcher")
|
||||
}
|
||||
|
||||
class AppsRedisSubscriberActor(connEventBus: InternalMessageBus, redisHost: String,
|
||||
redisPort: Int,
|
||||
channels: Seq[String] = Nil, patterns: Seq[String] = Nil)
|
||||
extends RedisSubscriberActor(
|
||||
new InetSocketAddress(redisHost, redisPort),
|
||||
channels, patterns, onConnectStatus = connected => { println(s"connected: $connected") }
|
||||
)
|
||||
with SystemConfiguration with ActorLogging {
|
||||
|
||||
override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) {
|
||||
case e: Exception => {
|
||||
val sw: StringWriter = new StringWriter()
|
||||
sw.write("An exception has been thrown on AppsRedisSubscriberActor, exception message [" + e.getMessage() + "] (full stacktrace below)\n")
|
||||
e.printStackTrace(new PrintWriter(sw))
|
||||
log.error(sw.toString())
|
||||
Resume
|
||||
}
|
||||
}
|
||||
|
||||
// Set the name of this client to be able to distinguish when doing
|
||||
// CLIENT LIST on redis-cli
|
||||
write(ClientSetname("Red5AppsSub").encodedRequest)
|
||||
|
||||
def onMessage(message: Message) {
|
||||
if (channels.contains(message.channel)) {
|
||||
//log.debug(s"RECEIVED:\n ${message.data.utf8String} \n")
|
||||
val receivedJsonMessage = new JsonMsgFromAkkaApps(message.channel, message.data.utf8String)
|
||||
connEventBus.publish(MsgFromConnBusMsg(fromAkkaAppsJsonChannel, receivedJsonMessage))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
def onPMessage(pmessage: PMessage) {
|
||||
// We don't use PSubscribe anymore, but an implementation of the method is required
|
||||
log.error("Should not be receiving a PMessage. It triggered on a match of pattern: " + pmessage.patternMatched)
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
package org.bigbluebutton.client.endpoint.redis
|
||||
|
||||
import scala.concurrent.duration._
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import akka.actor.ActorSystem
|
||||
import org.bigbluebutton.client.SystemConfiguration
|
||||
//import org.bigbluebutton.common.messages.BbbAppsIsAliveMessage
|
||||
|
||||
class KeepAliveRedisPublisher(val system: ActorSystem, sender: RedisPublisher) extends SystemConfiguration {
|
||||
|
||||
val startedOn = System.currentTimeMillis()
|
||||
|
||||
system.scheduler.schedule(2 seconds, 5 seconds) {
|
||||
// val msg = new BbbAppsIsAliveMessage(startedOn, System.currentTimeMillis())
|
||||
// sender.publish("bigbluebutton:from-bbb-apps:keepalive", msg.toJson())
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
package org.bigbluebutton.client.endpoint.redis
|
||||
|
||||
class MessageSender(publisher: RedisPublisher) {
|
||||
|
||||
def send(channel: String, data: String) {
|
||||
publisher.publish(channel, data)
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
package org.bigbluebutton.client.endpoint.redis
|
||||
|
||||
import redis.RedisClient
|
||||
import akka.actor.ActorSystem
|
||||
import akka.event.Logging
|
||||
import org.bigbluebutton.client.SystemConfiguration
|
||||
import akka.util.ByteString
|
||||
|
||||
class RedisPublisher(val system: ActorSystem) extends SystemConfiguration {
|
||||
|
||||
val redis = RedisClient(redisHost, redisPort)(system)
|
||||
|
||||
val log = Logging(system, getClass)
|
||||
|
||||
// Set the name of this client to be able to distinguish when doing
|
||||
// CLIENT LIST on redis-cli
|
||||
redis.clientSetname("Red5AppsPub")
|
||||
|
||||
def publish(channel: String, data: String) {
|
||||
//log.debug("PUBLISH TO [" + channel + "]: \n [" + data + "]")
|
||||
redis.publish(channel, ByteString(data))
|
||||
}
|
||||
|
||||
}
|
@ -1,102 +0,0 @@
|
||||
package org.bigbluebutton.client.meeting
|
||||
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
|
||||
import scala.collection.immutable.HashSet
|
||||
|
||||
class AllowedMessageNames {
|
||||
|
||||
}
|
||||
|
||||
object AllowedMessageNames {
|
||||
val MESSAGES = HashSet(
|
||||
// User Messages
|
||||
ValidateAuthTokenReqMsg.NAME,
|
||||
GetUsersMeetingReqMsg.NAME,
|
||||
GetGuestsWaitingApprovalReqMsg.NAME,
|
||||
UserJoinMeetingReqMsg.NAME,
|
||||
UserJoinMeetingAfterReconnectReqMsg.NAME,
|
||||
AssignPresenterReqMsg.NAME,
|
||||
ChangeUserEmojiCmdMsg.NAME,
|
||||
UserBroadcastCamStartMsg.NAME,
|
||||
UserBroadcastCamStopMsg.NAME,
|
||||
LogoutAndEndMeetingCmdMsg.NAME,
|
||||
GetRecordingStatusReqMsg.NAME,
|
||||
SetRecordingStatusCmdMsg.NAME,
|
||||
EjectUserFromMeetingCmdMsg.NAME,
|
||||
IsMeetingMutedReqMsg.NAME,
|
||||
LockUsersInMeetingCmdMsg.NAME,
|
||||
LockUserInMeetingCmdMsg.NAME,
|
||||
GetLockSettingsReqMsg.NAME,
|
||||
ChangeLockSettingsInMeetingCmdMsg.NAME,
|
||||
ChangeUserRoleCmdMsg.NAME,
|
||||
GetGuestPolicyReqMsg.NAME,
|
||||
SetGuestPolicyCmdMsg.NAME,
|
||||
GuestsWaitingApprovedMsg.NAME,
|
||||
|
||||
// Webcams
|
||||
GetWebcamsOnlyForModeratorReqMsg.NAME,
|
||||
|
||||
// Voice
|
||||
MuteMeetingCmdMsg.NAME,
|
||||
MuteAllExceptPresentersCmdMsg.NAME,
|
||||
MuteUserCmdMsg.NAME,
|
||||
EjectUserFromVoiceCmdMsg.NAME,
|
||||
|
||||
// Chat Messages
|
||||
GetGroupChatsReqMsg.NAME,
|
||||
GetGroupChatMsgsReqMsg.NAME,
|
||||
SendGroupChatMessageMsg.NAME,
|
||||
ClearPublicChatHistoryPubMsg.NAME,
|
||||
CreateGroupChatReqMsg.NAME,
|
||||
|
||||
// Presentation Messages
|
||||
ResizeAndMovePagePubMsg.NAME,
|
||||
SetCurrentPresentationPubMsg.NAME,
|
||||
SetCurrentPagePubMsg.NAME,
|
||||
GetAllPresentationPodsReqMsg.NAME,
|
||||
RemovePresentationPubMsg.NAME,
|
||||
SetPresentationDownloadablePubMsg.NAME,
|
||||
PresentationUploadTokenReqMsg.NAME,
|
||||
CreateNewPresentationPodPubMsg.NAME,
|
||||
RemovePresentationPodPubMsg.NAME,
|
||||
SetPresenterInPodReqMsg.NAME,
|
||||
|
||||
// Whiteboard Messages
|
||||
ModifyWhiteboardAccessPubMsg.NAME,
|
||||
DeleteWhiteboardAnnotationsPubMsg.NAME,
|
||||
ClearWhiteboardPubMsg.NAME,
|
||||
GetWhiteboardAnnotationsReqMsg.NAME,
|
||||
SendWhiteboardAnnotationsPubMsg.NAME,
|
||||
SendCursorPositionPubMsg.NAME,
|
||||
|
||||
// Polling Messages
|
||||
StartCustomPollReqMsg.NAME,
|
||||
StartPollReqMsg.NAME,
|
||||
StopPollReqMsg.NAME,
|
||||
RespondToPollReqMsg.NAME,
|
||||
ShowPollResultReqMsg.NAME,
|
||||
|
||||
// Screenshare Messages
|
||||
GetScreenshareStatusReqMsg.NAME,
|
||||
|
||||
// Caption Messages
|
||||
SendCaptionHistoryReqMsg.NAME,
|
||||
UpdateCaptionOwnerPubMsg.NAME,
|
||||
EditCaptionHistoryPubMsg.NAME,
|
||||
|
||||
// Layout Messages
|
||||
GetCurrentLayoutReqMsg.NAME,
|
||||
BroadcastLayoutMsg.NAME,
|
||||
|
||||
// Breakout
|
||||
CreateBreakoutRoomsCmdMsg.NAME,
|
||||
RequestBreakoutJoinURLReqMsg.NAME,
|
||||
TransferUserToMeetingRequestMsg.NAME,
|
||||
EndAllBreakoutRoomsMsg.NAME,
|
||||
BreakoutRoomsListMsg.NAME,
|
||||
|
||||
// System
|
||||
ClientToServerLatencyTracerMsg.NAME
|
||||
)
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
package org.bigbluebutton.client.meeting
|
||||
|
||||
import com.softwaremill.quicklens.modify
|
||||
|
||||
case class Connection(connId: String, sessionId: String, active: Boolean)
|
||||
|
||||
object Connections {
|
||||
|
||||
def setConnInactive(conns: Connections, conn: Connection): Connection = {
|
||||
val inactiveConn = modify(conn)(_.active).setTo(false)
|
||||
conns.save(inactiveConn)
|
||||
inactiveConn
|
||||
}
|
||||
|
||||
def findWithId(conns: Connections, id: String): Option[Connection] = {
|
||||
conns.toVector.find(c => c.connId == id)
|
||||
}
|
||||
|
||||
def findActiveConnection(conns: Connections): Option[Connection] = {
|
||||
conns.toVector.find(c => c.active)
|
||||
}
|
||||
|
||||
def add(conns: Connections, conn: Connection): Connection = {
|
||||
conns.save(conn)
|
||||
conn
|
||||
}
|
||||
|
||||
def remove(conns: Connections, connId: String): Option[Connection] = {
|
||||
conns.remove(connId)
|
||||
}
|
||||
|
||||
def noMoreConnections(conns: Connections): Boolean = {
|
||||
conns.toVector.length == 0
|
||||
}
|
||||
}
|
||||
|
||||
class Connections {
|
||||
private var conns: collection.immutable.HashMap[String, Connection] =
|
||||
new collection.immutable.HashMap[String, Connection]
|
||||
|
||||
private def toVector: Vector[Connection] = conns.values.toVector
|
||||
|
||||
private def save(conn: Connection): Connection = {
|
||||
conns += conn.connId -> conn
|
||||
conn
|
||||
}
|
||||
|
||||
private def remove(id: String): Option[Connection] = {
|
||||
val conn = conns.get(id)
|
||||
conn foreach { c => conns -= id }
|
||||
conn
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
package org.bigbluebutton.client.meeting
|
||||
|
||||
import akka.actor.ActorContext
|
||||
import org.bigbluebutton.client.bus.{ InternalMessageBus }
|
||||
|
||||
object Meeting {
|
||||
def apply(meetingId: String, connEventBus: InternalMessageBus)(implicit context: ActorContext) =
|
||||
new Meeting(meetingId, connEventBus)(context)
|
||||
}
|
||||
|
||||
class Meeting(val meetingId: String, connEventBus: InternalMessageBus)(implicit val context: ActorContext) {
|
||||
|
||||
val actorRef = context.actorOf(MeetingActor.props(meetingId, connEventBus), meetingId)
|
||||
}
|
@ -1,116 +0,0 @@
|
||||
package org.bigbluebutton.client.meeting
|
||||
|
||||
import akka.actor.{ Actor, ActorLogging, Props }
|
||||
import org.bigbluebutton.client.SystemConfiguration
|
||||
import org.bigbluebutton.client.bus._
|
||||
import org.bigbluebutton.common2.msgs.{ BbbCommonEnvJsNodeMsg, DisconnectAllClientsSysMsg, MessageTypes }
|
||||
|
||||
object MeetingActor {
|
||||
def props(meetingId: String, connEventBus: InternalMessageBus): Props =
|
||||
Props(classOf[MeetingActor], meetingId, connEventBus)
|
||||
}
|
||||
|
||||
class MeetingActor(val meetingId: String, connEventBus: InternalMessageBus)
|
||||
extends Actor with ActorLogging
|
||||
with SystemConfiguration {
|
||||
|
||||
private val userMgr = new UsersManager
|
||||
|
||||
def receive = {
|
||||
case msg: ClientConnectedMsg => handleConnectMsg(msg)
|
||||
case msg: ClientDisconnectedMsg => handleDisconnectMsg(msg)
|
||||
case msg: MsgFromClientMsg => handleMsgFromClientMsg(msg)
|
||||
case msg: BbbCommonEnvJsNodeMsg => handleBbbServerMsg(msg)
|
||||
// TODO: Should keep track of user lifecycle so we can remove when user leaves the meeting.
|
||||
}
|
||||
|
||||
private def createUser(id: String): User = {
|
||||
User(id, connEventBus, meetingId)
|
||||
}
|
||||
|
||||
def handleConnectMsg(msg: ClientConnectedMsg): Unit = {
|
||||
//log.debug("**** MeetingActor handleConnectMsg " + msg.connInfo.meetingId)
|
||||
UsersManager.findWithId(userMgr, msg.connInfo.userId) match {
|
||||
case Some(m) => m.actorRef forward (msg)
|
||||
case None =>
|
||||
val m = createUser(msg.connInfo.userId)
|
||||
UsersManager.add(userMgr, m)
|
||||
m.actorRef forward (msg)
|
||||
}
|
||||
}
|
||||
|
||||
def handleDisconnectMsg(msg: ClientDisconnectedMsg): Unit = {
|
||||
//log.debug("**** MeetingActor handleDisconnectMsg " + msg.connInfo.meetingId)
|
||||
for {
|
||||
m <- UsersManager.findWithId(userMgr, msg.connInfo.userId)
|
||||
} yield {
|
||||
m.actorRef forward (msg)
|
||||
}
|
||||
}
|
||||
|
||||
def handleMsgFromClientMsg(msg: MsgFromClientMsg): Unit = {
|
||||
//log.debug("**** MeetingActor handleMsgFromClient " + msg.json)
|
||||
for {
|
||||
m <- UsersManager.findWithId(userMgr, msg.connInfo.userId)
|
||||
} yield {
|
||||
m.actorRef forward (msg)
|
||||
}
|
||||
}
|
||||
|
||||
def handleBbbServerMsg(msg: BbbCommonEnvJsNodeMsg): Unit = {
|
||||
//log.debug("**** MeetingActor handleBbbServerMsg " + msg.envelope.name)
|
||||
for {
|
||||
msgType <- msg.envelope.routing.get("msgType")
|
||||
} yield {
|
||||
handleServerMsg(msgType, msg)
|
||||
}
|
||||
}
|
||||
|
||||
def handleServerMsg(msgType: String, msg: BbbCommonEnvJsNodeMsg): Unit = {
|
||||
//log.debug("**** MeetingActor handleServerMsg " + msg.envelope.name)
|
||||
msgType match {
|
||||
case MessageTypes.DIRECT => handleDirectMessage(msg)
|
||||
case MessageTypes.BROADCAST_TO_MEETING => handleBroadcastMessage(msg)
|
||||
case MessageTypes.SYSTEM => handleSystemMessage(msg)
|
||||
}
|
||||
}
|
||||
|
||||
private def forwardToUser(msg: BbbCommonEnvJsNodeMsg): Unit = {
|
||||
//log.debug("**** MeetingActor forwardToUser " + msg.envelope.name)
|
||||
for {
|
||||
userId <- msg.envelope.routing.get("userId")
|
||||
m <- UsersManager.findWithId(userMgr, userId)
|
||||
} yield {
|
||||
//log.debug("**** MeetingActor forwardToUser " + m.userId)
|
||||
m.actorRef forward (msg)
|
||||
}
|
||||
}
|
||||
|
||||
def handleDirectMessage(msg: BbbCommonEnvJsNodeMsg): Unit = {
|
||||
//log.debug("**** MeetingActor handleDirectMessage " + msg.envelope.name)
|
||||
// In case we want to handle specific messages. We can do it here.
|
||||
forwardToUser(msg)
|
||||
}
|
||||
|
||||
def handleBroadcastMessage(msg: BbbCommonEnvJsNodeMsg): Unit = {
|
||||
// In case we want to handle specific messages. We can do it here.
|
||||
//connEventBus.publish(MsgFromConnBusMsg(toClientChannel, BroadcastMsgToMeeting(meetingId, msg)))
|
||||
|
||||
UsersManager.findAll(userMgr) foreach { u =>
|
||||
u.actorRef forward (msg)
|
||||
}
|
||||
}
|
||||
|
||||
def handleSystemMessage(msg: BbbCommonEnvJsNodeMsg): Unit = {
|
||||
// In case we want to handle specific messages. We can do it here.
|
||||
//msg.envelope.name match {
|
||||
// case DisconnectAllClientsSysMsg.NAME =>
|
||||
// connEventBus.publish(MsgFromConnBusMsg(toClientChannel, DisconnectAllMeetingClientsMsg(meetingId)))
|
||||
// case _ => forwardToUser(msg)
|
||||
//}
|
||||
|
||||
UsersManager.findAll(userMgr) foreach { u =>
|
||||
u.actorRef forward (msg)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
package org.bigbluebutton.client.meeting
|
||||
|
||||
object MeetingManager {
|
||||
def findWithMeetingId(manager: MeetingManager, meetingId: String): Option[Meeting] = {
|
||||
manager.toVector.find(m => m.meetingId == meetingId)
|
||||
}
|
||||
|
||||
def remove(manager: MeetingManager, meetingId: String): Option[Meeting] = {
|
||||
manager.remove(meetingId)
|
||||
}
|
||||
|
||||
def add(manager: MeetingManager, meeting: Meeting): Meeting = {
|
||||
manager.save(meeting)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class MeetingManager {
|
||||
private var meetings = new collection.immutable.HashMap[String, Meeting]
|
||||
|
||||
private def toVector: Vector[Meeting] = meetings.values.toVector
|
||||
|
||||
private def save(meeting: Meeting): Meeting = {
|
||||
meetings += meeting.meetingId -> meeting
|
||||
meeting
|
||||
}
|
||||
|
||||
private def remove(id: String): Option[Meeting] = {
|
||||
val meeting = meetings.get(id)
|
||||
meeting foreach (u => meetings -= id)
|
||||
meeting
|
||||
}
|
||||
}
|
@ -1,112 +0,0 @@
|
||||
package org.bigbluebutton.client.meeting
|
||||
|
||||
import akka.actor.{ Actor, ActorLogging, Props }
|
||||
import org.bigbluebutton.client.bus._
|
||||
import org.bigbluebutton.common2.msgs.{ BbbCommonEnvJsNodeMsg, MessageTypes }
|
||||
|
||||
object MeetingManagerActor {
|
||||
def props(connEventBus: InternalMessageBus): Props =
|
||||
Props(classOf[MeetingManagerActor], connEventBus)
|
||||
}
|
||||
|
||||
class MeetingManagerActor(connEventBus: InternalMessageBus)
|
||||
extends Actor with ActorLogging {
|
||||
|
||||
private val meetingMgr = new MeetingManager
|
||||
|
||||
def receive = {
|
||||
case msg: ClientConnectedMsg => handleConnectMsg(msg)
|
||||
case msg: ClientDisconnectedMsg => handleDisconnectMsg(msg)
|
||||
case msg: MsgFromClientMsg => handleMsgFromClientMsg(msg)
|
||||
case msg: MsgFromAkkaApps => handleBbbServerMsg(msg)
|
||||
// TODO we should monitor meeting lifecycle so we can remove when meeting ends.
|
||||
}
|
||||
|
||||
def createMeeting(meetingId: String): Meeting = {
|
||||
Meeting(meetingId, connEventBus)
|
||||
}
|
||||
|
||||
def handleConnectMsg(msg: ClientConnectedMsg): Unit = {
|
||||
//log.debug("****** Received handleConnectMsg " + msg)
|
||||
MeetingManager.findWithMeetingId(meetingMgr, msg.connInfo.meetingId) match {
|
||||
case Some(m) => m.actorRef forward (msg)
|
||||
case None =>
|
||||
val m = createMeeting(msg.connInfo.meetingId)
|
||||
MeetingManager.add(meetingMgr, m)
|
||||
m.actorRef forward (msg)
|
||||
}
|
||||
}
|
||||
|
||||
def handleDisconnectMsg(msg: ClientDisconnectedMsg): Unit = {
|
||||
//log.debug("****** Received handleDisconnectMsg " + msg)
|
||||
for {
|
||||
m <- MeetingManager.findWithMeetingId(meetingMgr, msg.connInfo.meetingId)
|
||||
} yield {
|
||||
m.actorRef forward (msg)
|
||||
}
|
||||
}
|
||||
|
||||
def handleMsgFromClientMsg(msg: MsgFromClientMsg): Unit = {
|
||||
//log.debug("**** MeetingManagerActor handleMsgFromClient " + msg.json)
|
||||
for {
|
||||
m <- MeetingManager.findWithMeetingId(meetingMgr, msg.connInfo.meetingId)
|
||||
} yield {
|
||||
m.actorRef forward (msg)
|
||||
}
|
||||
}
|
||||
|
||||
def handleBbbServerMsg(msg: MsgFromAkkaApps): Unit = {
|
||||
//log.debug("**** MeetingManagerActor handleBbbServerMsg " + msg.envelope.name)
|
||||
for {
|
||||
msgType <- msg.payload.envelope.routing.get("msgType")
|
||||
} yield {
|
||||
handleServerMsg(msgType, msg.payload)
|
||||
}
|
||||
}
|
||||
|
||||
def handleServerMsg(msgType: String, msg: BbbCommonEnvJsNodeMsg): Unit = {
|
||||
//log.debug("**** MeetingManagerActor handleServerMsg " + msg.envelope.name)
|
||||
msgType match {
|
||||
case MessageTypes.DIRECT => handleDirectMessage(msg)
|
||||
case MessageTypes.BROADCAST_TO_MEETING => handleBroadcastMessage(msg)
|
||||
case MessageTypes.SYSTEM => handleSystemMessage(msg)
|
||||
}
|
||||
}
|
||||
|
||||
private def forwardToMeeting(msg: BbbCommonEnvJsNodeMsg): Unit = {
|
||||
msg.envelope.routing.get("meetingId") match {
|
||||
case Some(meetingId2) => //log.debug("**** MeetingManagerActor forwardToMeeting. Found " + meetingId2)
|
||||
MeetingManager.findWithMeetingId(meetingMgr, meetingId2) match {
|
||||
case Some(meetingId2) => //log.debug("**** MeetingManagerActor forwardToMeeting. Found " + meetingId2.meetingId)
|
||||
case None => //log.debug("**** MeetingManagerActor forwardToMeeting. Could not find meetingId")
|
||||
}
|
||||
case None => log.debug("**** MeetingManagerActor forwardToMeeting. Could not find meetingId")
|
||||
}
|
||||
|
||||
for {
|
||||
meetingId <- msg.envelope.routing.get("meetingId")
|
||||
m <- MeetingManager.findWithMeetingId(meetingMgr, meetingId)
|
||||
} yield {
|
||||
//log.debug("**** MeetingManagerActor forwardToMeeting. " + m.meetingId)
|
||||
m.actorRef forward (msg)
|
||||
}
|
||||
}
|
||||
|
||||
def handleDirectMessage(msg: BbbCommonEnvJsNodeMsg): Unit = {
|
||||
//log.debug("**** MeetingManagerActor handleDirectMessage " + msg.envelope.name)
|
||||
// In case we want to handle specific message. We can do it here.
|
||||
forwardToMeeting(msg)
|
||||
}
|
||||
|
||||
def handleBroadcastMessage(msg: BbbCommonEnvJsNodeMsg): Unit = {
|
||||
// log.debug("**** MeetingManagerActor handleBroadcastMessage " + msg.envelope.name)
|
||||
// In case we want to handle specific message. We can do it here.
|
||||
forwardToMeeting(msg)
|
||||
}
|
||||
|
||||
def handleSystemMessage(msg: BbbCommonEnvJsNodeMsg): Unit = {
|
||||
//log.debug("**** MeetingManagerActor handleSystemMessage " + msg.envelope.name)
|
||||
// In case we want to handle specific message. We can do it here.
|
||||
forwardToMeeting(msg)
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
package org.bigbluebutton.client.meeting
|
||||
|
||||
import akka.actor.ActorContext
|
||||
import org.bigbluebutton.client.bus.{ InternalMessageBus }
|
||||
|
||||
object User {
|
||||
def apply(
|
||||
userId: String,
|
||||
connEventBus: InternalMessageBus,
|
||||
meetingId: String
|
||||
)(implicit context: ActorContext): User =
|
||||
new User(userId, connEventBus, meetingId)(context)
|
||||
}
|
||||
|
||||
class User(
|
||||
val userId: String,
|
||||
connEventBus: InternalMessageBus,
|
||||
meetingId: String
|
||||
)(implicit val context: ActorContext) {
|
||||
|
||||
val actorRef = context.actorOf(UserActor.props(userId, connEventBus, meetingId), meetingId + "-" + userId)
|
||||
}
|
@ -1,214 +0,0 @@
|
||||
package org.bigbluebutton.client.meeting
|
||||
|
||||
import akka.actor.{ Actor, ActorLogging, Props }
|
||||
import org.bigbluebutton.client.{ SystemConfiguration }
|
||||
import org.bigbluebutton.client.bus._
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.common2.util.JsonUtil
|
||||
import com.fasterxml.jackson.databind.JsonNode
|
||||
|
||||
import scala.util.{ Failure, Success }
|
||||
|
||||
object UserActor {
|
||||
def props(
|
||||
userId: String,
|
||||
connEventBus: InternalMessageBus,
|
||||
meetingId: String
|
||||
): Props =
|
||||
Props(classOf[UserActor], userId, connEventBus, meetingId)
|
||||
}
|
||||
|
||||
class UserActor(
|
||||
val userId: String,
|
||||
connEventBus: InternalMessageBus,
|
||||
meetingId: String
|
||||
)
|
||||
extends Actor with ActorLogging with SystemConfiguration {
|
||||
|
||||
private val conns = new Connections
|
||||
private var authorized = false
|
||||
|
||||
def receive = {
|
||||
|
||||
case msg: ClientConnectedMsg => handleConnectMsg(msg)
|
||||
case msg: ClientDisconnectedMsg => handleDisconnectMsg(msg)
|
||||
case msg: MsgFromClientMsg => handleMsgFromClientMsg(msg, true)
|
||||
case msg: BbbCommonEnvJsNodeMsg => handleBbbServerMsg(msg)
|
||||
case _ => log.debug("***** UserActor cannot handle msg ")
|
||||
}
|
||||
|
||||
private def createConnection(id: String, sessionId: String, active: Boolean): Connection = {
|
||||
Connection(id, sessionId, active)
|
||||
}
|
||||
|
||||
def handleConnectMsg(msg: ClientConnectedMsg): Unit = {
|
||||
log.debug("**** UserActor handleConnectMsg " + msg.connInfo.userId)
|
||||
Connections.findWithId(conns, msg.connInfo.connId) match {
|
||||
case Some(m) => log.warning("Connect message on same connection id. " + JsonUtil.toJson(msg.connInfo))
|
||||
case None =>
|
||||
for {
|
||||
activeConn <- Connections.findActiveConnection(conns)
|
||||
} yield {
|
||||
Connections.setConnInactive(conns, activeConn)
|
||||
}
|
||||
val m = createConnection(msg.connInfo.connId, msg.connInfo.connId, true)
|
||||
log.debug("**** UserActor create connection " + m.connId)
|
||||
Connections.add(conns, m)
|
||||
authorized = false
|
||||
}
|
||||
}
|
||||
|
||||
def handleDisconnectMsg(msg: ClientDisconnectedMsg): Unit = {
|
||||
log.debug("**** UserActor handleDisconnectMsg " + msg.connInfo.userId)
|
||||
for {
|
||||
m <- Connections.findWithId(conns, msg.connInfo.connId)
|
||||
} yield {
|
||||
log.debug("**** UserActor remove connection " + m.connId)
|
||||
Connections.remove(conns, m.connId)
|
||||
}
|
||||
|
||||
if (Connections.noMoreConnections(conns)) {
|
||||
val json = buildUserLeavingMessage(msg.connInfo)
|
||||
val msgFromClient = MsgFromClientMsg(msg.connInfo, json)
|
||||
handleMsgFromClientMsg(msgFromClient, false)
|
||||
}
|
||||
}
|
||||
|
||||
private def buildUserLeavingMessage(connInfo: ConnInfo2): String = {
|
||||
val header = BbbClientMsgHeader(UserLeaveReqMsg.NAME, meetingId, userId)
|
||||
val body = UserLeaveReqMsgBody(userId, connInfo.connId)
|
||||
val event = UserLeaveReqMsg(header, body)
|
||||
JsonUtil.toJson(event)
|
||||
}
|
||||
|
||||
private def buildEjectUserFromMeetingSysMsg(meetingId: String, userId: String): String = {
|
||||
val header = BbbClientMsgHeader(EjectUserFromMeetingSysMsg.NAME, meetingId, userId)
|
||||
val body = EjectUserFromMeetingSysMsgBody(userId, "bbb-apps")
|
||||
val event = EjectUserFromMeetingSysMsg(header, body)
|
||||
JsonUtil.toJson(event)
|
||||
}
|
||||
|
||||
private def sendEjectUserFromMeetingToAkkaApps(connInfo: ConnInfo2, meetingId: String, userId: String): Unit = {
|
||||
val json = buildEjectUserFromMeetingSysMsg(meetingId, userId)
|
||||
val msgFromClient = MsgFromClientMsg(connInfo, json)
|
||||
handleMsgFromClientMsg(msgFromClient, false)
|
||||
}
|
||||
|
||||
def handleMsgFromClientMsg(msg: MsgFromClientMsg, applyWhitelist: Boolean): Unit = {
|
||||
println("************* MESSAGE FROM CLIENT *********** \n" + msg.json)
|
||||
def convertToJsonNode(json: String): Option[JsonNode] = {
|
||||
JsonUtil.toJsonNode(json) match {
|
||||
case Success(jsonNode) => Some(jsonNode)
|
||||
case Failure(ex) =>
|
||||
log.error("Failed to process client message body " + ex)
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
object Deserializer extends Deserializer
|
||||
|
||||
val (result, error) = Deserializer.toBbbCoreMessageFromClient(msg.json)
|
||||
result match {
|
||||
case Some(msgFromClient) =>
|
||||
if (applyWhitelist && !AllowedMessageNames.MESSAGES.contains(msgFromClient.header.name)) {
|
||||
// If the message that the client sends isn't allowed disconnect them.
|
||||
log.error("User (" + userId + ") tried to send a non-whitelisted message with name=[" + msgFromClient.header.name + "] attempting to disconnect them")
|
||||
for {
|
||||
conn <- Connections.findActiveConnection(conns)
|
||||
} yield {
|
||||
connEventBus.publish(MsgFromConnBusMsg("clientActor-" + conn.connId, DisconnectClientMsg(meetingId, conn.connId)))
|
||||
// Tell Akka apps to eject user from meeting.
|
||||
sendEjectUserFromMeetingToAkkaApps(msg.connInfo, meetingId, userId)
|
||||
}
|
||||
} else {
|
||||
// Override the meetingId and userId on the message from client. This
|
||||
// will prevent spoofing of messages. (ralam oct 30, 2017)
|
||||
val newHeader = BbbClientMsgHeader(msgFromClient.header.name, meetingId, userId)
|
||||
val msgClient = msgFromClient.copy(header = newHeader)
|
||||
|
||||
val routing = Routing.addMsgFromClientRouting(msgClient.header.meetingId, msgClient.header.userId)
|
||||
val envelope = new BbbCoreEnvelope(msgClient.header.name, routing)
|
||||
|
||||
if (msgClient.header.name == "ClientToServerLatencyTracerMsg") {
|
||||
log.info("-- trace -- " + msg.json)
|
||||
}
|
||||
|
||||
val json = JsonUtil.toJson(msgClient)
|
||||
for {
|
||||
jsonNode <- convertToJsonNode(json)
|
||||
} yield {
|
||||
val akkaMsg = BbbCommonEnvJsNodeMsg(envelope, jsonNode)
|
||||
println("****** FORWARDING TO AKKA APPS ******")
|
||||
connEventBus.publish(MsgFromConnBusMsg(toAkkaAppsChannel, MsgToAkkaApps(akkaMsg)))
|
||||
}
|
||||
}
|
||||
case None =>
|
||||
log.error("Failed to convert message with error: " + error)
|
||||
}
|
||||
}
|
||||
|
||||
def handleBbbServerMsg(msg: BbbCommonEnvJsNodeMsg): Unit = {
|
||||
//log.debug("**** UserActor handleBbbServerMsg " + msg)
|
||||
for {
|
||||
msgType <- msg.envelope.routing.get("msgType")
|
||||
} yield {
|
||||
handleServerMsg(msgType, msg)
|
||||
}
|
||||
}
|
||||
|
||||
def handleServerMsg(msgType: String, msg: BbbCommonEnvJsNodeMsg): Unit = {
|
||||
// log.debug("**** UserActor handleServerMsg " + msg)
|
||||
println("************* MESSAGE FROM SERVER *********** \n" + msg)
|
||||
msgType match {
|
||||
case MessageTypes.DIRECT => handleDirectMessage(msg)
|
||||
case MessageTypes.BROADCAST_TO_MEETING => handleBroadcastMessage(msg)
|
||||
case MessageTypes.SYSTEM => handleSystemMessage(msg)
|
||||
}
|
||||
}
|
||||
|
||||
private def forwardToUser(msg: BbbCommonEnvJsNodeMsg): Unit = {
|
||||
//println("UserActor forwardToUser. Forwarding to connection. " + msg)
|
||||
for {
|
||||
conn <- Connections.findActiveConnection(conns)
|
||||
} yield {
|
||||
msg.envelope.name match {
|
||||
case ValidateAuthTokenRespMsg.NAME =>
|
||||
val core = msg.core.asInstanceOf[JsonNode]
|
||||
val body = core.get("body")
|
||||
val valid = body.get("valid")
|
||||
if (valid.asBoolean) {
|
||||
authorized = true
|
||||
}
|
||||
case _ => // let it pass through
|
||||
}
|
||||
if (authorized) {
|
||||
connEventBus.publish(MsgFromConnBusMsg("clientActor-" + conn.connId, DirectMsgToClient(meetingId, conn.connId, msg)))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
def handleDirectMessage(msg: BbbCommonEnvJsNodeMsg): Unit = {
|
||||
// In case we want to handle specific messages. We can do it here.
|
||||
forwardToUser(msg)
|
||||
}
|
||||
|
||||
def handleBroadcastMessage(msg: BbbCommonEnvJsNodeMsg): Unit = {
|
||||
// In case we want to handle specific messages. We can do it here.
|
||||
forwardToUser(msg)
|
||||
}
|
||||
|
||||
def handleSystemMessage(msg: BbbCommonEnvJsNodeMsg): Unit = {
|
||||
for {
|
||||
conn <- Connections.findActiveConnection(conns)
|
||||
} yield {
|
||||
msg.envelope.name match {
|
||||
case DisconnectClientSysMsg.NAME =>
|
||||
connEventBus.publish(MsgFromConnBusMsg("clientActor-" + conn.connId, DisconnectClientMsg(meetingId, conn.connId)))
|
||||
case DisconnectAllClientsSysMsg.NAME =>
|
||||
connEventBus.publish(MsgFromConnBusMsg("clientActor-" + conn.connId, DisconnectClientMsg(meetingId, conn.connId)))
|
||||
case _ => log.warning("Unhandled system messsage " + msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
package org.bigbluebutton.client.meeting
|
||||
|
||||
object UsersManager {
|
||||
|
||||
def findAll(manager: UsersManager): Vector[User] = {
|
||||
manager.toVector
|
||||
}
|
||||
|
||||
def findWithId(manager: UsersManager, id: String): Option[User] = {
|
||||
manager.toVector.find(m => m.userId == id)
|
||||
}
|
||||
|
||||
def remove(manager: UsersManager, id: String): Option[User] = {
|
||||
manager.remove(id)
|
||||
}
|
||||
|
||||
def add(manager: UsersManager, user: User): User = {
|
||||
manager.save(user)
|
||||
}
|
||||
}
|
||||
|
||||
class UsersManager {
|
||||
private var users = new collection.immutable.HashMap[String, User]
|
||||
|
||||
private def toVector: Vector[User] = users.values.toVector
|
||||
|
||||
private def save(user: User): User = {
|
||||
users += user.userId -> user
|
||||
user
|
||||
}
|
||||
|
||||
private def remove(id: String): Option[User] = {
|
||||
val user = users.get(id)
|
||||
user foreach (u => users -= id)
|
||||
user
|
||||
}
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
<!--
|
||||
#%L
|
||||
distributed-chat-service
|
||||
%%
|
||||
Copyright (C) 2015 Zanclus Consulting
|
||||
%%
|
||||
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.
|
||||
#L%
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Distributed Chat Service</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/sockjs/0.3.4/sockjs.min.js"></script>
|
||||
<script src="vertxbus.js"></script>
|
||||
<style>
|
||||
.inset {
|
||||
box-shadow: inset 0 0 4px #000000;
|
||||
-moz-box-shadow: inset 0 0 4px #000000;
|
||||
-webkit-box-shadow: inset 0 0 4px #000000;
|
||||
width: 400px;
|
||||
border-width: 4px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
input.inset {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
div.inset {
|
||||
height: 500px;
|
||||
white-space: pre-wrap
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
//var eb = new vertx.EventBus("https://192.168.23.33:3001/eventbus");
|
||||
var eb = new vertx.EventBus("http://192.168.246.131:3001/eventbus");
|
||||
eb.onopen = function () {
|
||||
eb.registerHandler("chat.to.client", function (msg) {
|
||||
$('#chat').append(msg + "\n");
|
||||
});
|
||||
|
||||
eb.send("foo-bar", "ValidateAuthToken", function(msg) {
|
||||
$('#chat').append("reply: " + msg + "\n");
|
||||
});
|
||||
};
|
||||
|
||||
function send(event) {
|
||||
if (event.keyCode == 13 || event.which == 13) {
|
||||
var message = $('#input').val();
|
||||
if (message.length > 0) {
|
||||
console.log($('#input'));
|
||||
eb.publish("chat.to.server", message);
|
||||
$('#input').val("");
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<div id="chat" class="inset"></div>
|
||||
<input id="input" type="text" onkeydown="send(event)" class="inset">
|
||||
</body>
|
||||
</html>
|
@ -1,19 +0,0 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate"/>
|
||||
<meta http-equiv="Pragma" content="no-cache"/>
|
||||
<meta http-equiv="Expires" content="0"/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<h2>You can only see this page if you are logged in!</h2>
|
||||
|
||||
<br>
|
||||
<br>
|
||||
<a href="/logout">Logout</a>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,228 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011-2013 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
|
||||
var vertx = vertx || {};
|
||||
|
||||
!function(factory) {
|
||||
if (typeof define === "function" && define.amd) {
|
||||
// Expose as an AMD module with SockJS dependency.
|
||||
// "vertxbus" and "sockjs" names are used because
|
||||
// AMD module names are derived from file names.
|
||||
define("vertxbus", ["sockjs"], factory);
|
||||
} else {
|
||||
// No AMD-compliant loader
|
||||
factory(SockJS);
|
||||
}
|
||||
}(function(SockJS) {
|
||||
|
||||
vertx.EventBus = function(url, options) {
|
||||
|
||||
var that = this;
|
||||
var sockJSConn = new SockJS(url, undefined, options);
|
||||
var handlerMap = {};
|
||||
var replyHandlers = {};
|
||||
var state = vertx.EventBus.CONNECTING;
|
||||
var pingTimerID = null;
|
||||
var pingInterval = null;
|
||||
if (options) {
|
||||
pingInterval = options['vertxbus_ping_interval'];
|
||||
}
|
||||
if (!pingInterval) {
|
||||
pingInterval = 5000;
|
||||
}
|
||||
|
||||
that.onopen = null;
|
||||
that.onclose = null;
|
||||
|
||||
that.send = function(address, message, replyHandler) {
|
||||
sendOrPub("send", address, message, replyHandler)
|
||||
}
|
||||
|
||||
that.publish = function(address, message) {
|
||||
sendOrPub("publish", address, message, null)
|
||||
}
|
||||
|
||||
that.registerHandler = function(address, handler) {
|
||||
checkSpecified("address", 'string', address);
|
||||
checkSpecified("handler", 'function', handler);
|
||||
checkOpen();
|
||||
var handlers = handlerMap[address];
|
||||
if (!handlers) {
|
||||
handlers = [handler];
|
||||
handlerMap[address] = handlers;
|
||||
// First handler for this address so we should register the connection
|
||||
var msg = { type : "register",
|
||||
address: address };
|
||||
sockJSConn.send(JSON.stringify(msg));
|
||||
} else {
|
||||
handlers[handlers.length] = handler;
|
||||
}
|
||||
}
|
||||
|
||||
that.unregisterHandler = function(address, handler) {
|
||||
checkSpecified("address", 'string', address);
|
||||
checkSpecified("handler", 'function', handler);
|
||||
checkOpen();
|
||||
var handlers = handlerMap[address];
|
||||
if (handlers) {
|
||||
var idx = handlers.indexOf(handler);
|
||||
if (idx != -1) handlers.splice(idx, 1);
|
||||
if (handlers.length == 0) {
|
||||
// No more local handlers so we should unregister the connection
|
||||
|
||||
var msg = { type : "unregister",
|
||||
address: address};
|
||||
sockJSConn.send(JSON.stringify(msg));
|
||||
delete handlerMap[address];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
that.close = function() {
|
||||
checkOpen();
|
||||
state = vertx.EventBus.CLOSING;
|
||||
sockJSConn.close();
|
||||
}
|
||||
|
||||
that.readyState = function() {
|
||||
return state;
|
||||
}
|
||||
|
||||
sockJSConn.onopen = function() {
|
||||
// Send the first ping then send a ping every pingInterval milliseconds
|
||||
sendPing();
|
||||
pingTimerID = setInterval(sendPing, pingInterval);
|
||||
state = vertx.EventBus.OPEN;
|
||||
if (that.onopen) {
|
||||
that.onopen();
|
||||
}
|
||||
};
|
||||
|
||||
sockJSConn.onclose = function() {
|
||||
state = vertx.EventBus.CLOSED;
|
||||
if (pingTimerID) clearInterval(pingTimerID);
|
||||
if (that.onclose) {
|
||||
that.onclose();
|
||||
}
|
||||
};
|
||||
|
||||
sockJSConn.onmessage = function(e) {
|
||||
var msg = e.data;
|
||||
var json = JSON.parse(msg);
|
||||
var type = json.type;
|
||||
if (type === 'err') {
|
||||
console.error("Error received on connection: " + json.body);
|
||||
return;
|
||||
}
|
||||
var body = json.body;
|
||||
var replyAddress = json.replyAddress;
|
||||
var address = json.address;
|
||||
var replyHandler;
|
||||
if (replyAddress) {
|
||||
replyHandler = function(reply, replyHandler) {
|
||||
// Send back reply
|
||||
that.send(replyAddress, reply, replyHandler);
|
||||
};
|
||||
}
|
||||
var handlers = handlerMap[address];
|
||||
if (handlers) {
|
||||
// We make a copy since the handler might get unregistered from within the
|
||||
// handler itself, which would screw up our iteration
|
||||
var copy = handlers.slice(0);
|
||||
for (var i = 0; i < copy.length; i++) {
|
||||
copy[i](body, replyHandler);
|
||||
}
|
||||
} else {
|
||||
// Might be a reply message
|
||||
var handler = replyHandlers[address];
|
||||
if (handler) {
|
||||
delete replyHandlers[address];
|
||||
handler(body, replyHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function sendPing() {
|
||||
var msg = {
|
||||
type: "ping"
|
||||
}
|
||||
sockJSConn.send(JSON.stringify(msg));
|
||||
}
|
||||
|
||||
function sendOrPub(sendOrPub, address, message, replyHandler) {
|
||||
checkSpecified("address", 'string', address);
|
||||
checkSpecified("replyHandler", 'function', replyHandler, true);
|
||||
checkOpen();
|
||||
var envelope = { type : sendOrPub,
|
||||
address: address,
|
||||
body: message };
|
||||
if (replyHandler) {
|
||||
var replyAddress = makeUUID();
|
||||
envelope.replyAddress = replyAddress;
|
||||
replyHandlers[replyAddress] = replyHandler;
|
||||
}
|
||||
var str = JSON.stringify(envelope);
|
||||
sockJSConn.send(str);
|
||||
}
|
||||
|
||||
function checkOpen() {
|
||||
if (state != vertx.EventBus.OPEN) {
|
||||
throw new Error('INVALID_STATE_ERR');
|
||||
}
|
||||
}
|
||||
|
||||
function checkSpecified(paramName, paramType, param, optional) {
|
||||
if (!optional && !param) {
|
||||
throw new Error("Parameter " + paramName + " must be specified");
|
||||
}
|
||||
if (param && typeof param != paramType) {
|
||||
throw new Error("Parameter " + paramName + " must be of type " + paramType);
|
||||
}
|
||||
}
|
||||
|
||||
function isFunction(obj) {
|
||||
return !!(obj && obj.constructor && obj.call && obj.apply);
|
||||
}
|
||||
|
||||
function makeUUID(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
|
||||
.replace(/[xy]/g,function(a,b){return b=Math.random()*16,(a=="y"?b&3|8:b|0).toString(16)})}
|
||||
|
||||
}
|
||||
|
||||
vertx.EventBus.CONNECTING = 0;
|
||||
vertx.EventBus.OPEN = 1;
|
||||
vertx.EventBus.CLOSING = 2;
|
||||
vertx.EventBus.CLOSED = 3;
|
||||
|
||||
return vertx.EventBus;
|
||||
|
||||
});
|
@ -1,76 +0,0 @@
|
||||
<!--
|
||||
#%L
|
||||
distributed-chat-service
|
||||
%%
|
||||
Copyright (C) 2015 Zanclus Consulting
|
||||
%%
|
||||
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.
|
||||
#L%
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Distributed Chat Service</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/sockjs/0.3.4/sockjs.min.js"></script>
|
||||
<script src="vertxbus.js"></script>
|
||||
<style>
|
||||
.inset {
|
||||
box-shadow: inset 0 0 4px #000000;
|
||||
-moz-box-shadow: inset 0 0 4px #000000;
|
||||
-webkit-box-shadow: inset 0 0 4px #000000;
|
||||
width: 400px;
|
||||
border-width: 4px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
input.inset {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
div.inset {
|
||||
height: 500px;
|
||||
white-space: pre-wrap
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
//var eb = new vertx.EventBus("https://192.168.23.33:3001/eventbus");
|
||||
var eb = new vertx.EventBus("http://192.168.246.131:3001/eventbus");
|
||||
eb.onopen = function () {
|
||||
eb.registerHandler("chat.to.client", function (msg) {
|
||||
$('#chat').append(msg + "\n");
|
||||
});
|
||||
|
||||
eb.send("foo-bar", "ValidateAuthToken", function(msg) {
|
||||
$('#chat').append("reply: " + msg + "\n");
|
||||
});
|
||||
};
|
||||
|
||||
function send(event) {
|
||||
if (event.keyCode == 13 || event.which == 13) {
|
||||
var message = $('#input').val();
|
||||
if (message.length > 0) {
|
||||
console.log($('#input'));
|
||||
eb.publish("chat.to.server", message);
|
||||
$('#input').val("");
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<div id="chat" class="inset"></div>
|
||||
<input id="input" type="text" onkeydown="send(event)" class="inset">
|
||||
</body>
|
||||
</html>
|
@ -1,15 +0,0 @@
|
||||
<html>
|
||||
|
||||
<body>
|
||||
|
||||
<h1>Web site with public and private pages</h1>
|
||||
|
||||
<br>
|
||||
<br>
|
||||
<a href="private/chat.html">Private page - login is required</a>
|
||||
|
||||
<br><br>
|
||||
|
||||
<a href="page1.html">Public page - no login required</a>
|
||||
</body>
|
||||
</html>
|
@ -1,29 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate"/>
|
||||
<meta http-equiv="Pragma" content="no-cache"/>
|
||||
<meta http-equiv="Expires" content="0"/>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Please login</h2><br>
|
||||
|
||||
<br>
|
||||
(Username is 'tim', password is 'sausages')
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<form action="/loginhandler" method="post">
|
||||
<div>
|
||||
<label>Username:</label>
|
||||
<input type="text" name="username"/>
|
||||
</div>
|
||||
<div>
|
||||
<label>Password:</label>
|
||||
<input type="password" name="password"/>
|
||||
</div>
|
||||
<div>
|
||||
<input type="submit" value="Log In"/>
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
@ -1,11 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Welcome to page1!</h1>
|
||||
|
||||
<br>
|
||||
This page does not require login - anyone can see it
|
||||
</body>
|
||||
</html>
|
@ -1,35 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
<script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/sockjs/0.3.4/sockjs.min.js"></script>
|
||||
<script src="vertxbus.js"></script>
|
||||
</head>
|
||||
|
||||
<style>
|
||||
.news {
|
||||
font-size: 20pt;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="news">Latest news: </div><br>
|
||||
<div id="status" class="news"></div>
|
||||
|
||||
<script>
|
||||
|
||||
var eb = new vertx.EventBus("http://192.168.23.33:3000/eventbus");
|
||||
|
||||
eb.onopen = function() {
|
||||
eb.registerHandler("news-feed", function(msg) {
|
||||
var str = "<code>" + msg + "</code><br>";
|
||||
$('#status').prepend(str);
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -1,228 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011-2013 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
|
||||
var vertx = vertx || {};
|
||||
|
||||
!function(factory) {
|
||||
if (typeof define === "function" && define.amd) {
|
||||
// Expose as an AMD module with SockJS dependency.
|
||||
// "vertxbus" and "sockjs" names are used because
|
||||
// AMD module names are derived from file names.
|
||||
define("vertxbus", ["sockjs"], factory);
|
||||
} else {
|
||||
// No AMD-compliant loader
|
||||
factory(SockJS);
|
||||
}
|
||||
}(function(SockJS) {
|
||||
|
||||
vertx.EventBus = function(url, options) {
|
||||
|
||||
var that = this;
|
||||
var sockJSConn = new SockJS(url, undefined, options);
|
||||
var handlerMap = {};
|
||||
var replyHandlers = {};
|
||||
var state = vertx.EventBus.CONNECTING;
|
||||
var pingTimerID = null;
|
||||
var pingInterval = null;
|
||||
if (options) {
|
||||
pingInterval = options['vertxbus_ping_interval'];
|
||||
}
|
||||
if (!pingInterval) {
|
||||
pingInterval = 5000;
|
||||
}
|
||||
|
||||
that.onopen = null;
|
||||
that.onclose = null;
|
||||
|
||||
that.send = function(address, message, replyHandler) {
|
||||
sendOrPub("send", address, message, replyHandler)
|
||||
}
|
||||
|
||||
that.publish = function(address, message) {
|
||||
sendOrPub("publish", address, message, null)
|
||||
}
|
||||
|
||||
that.registerHandler = function(address, handler) {
|
||||
checkSpecified("address", 'string', address);
|
||||
checkSpecified("handler", 'function', handler);
|
||||
checkOpen();
|
||||
var handlers = handlerMap[address];
|
||||
if (!handlers) {
|
||||
handlers = [handler];
|
||||
handlerMap[address] = handlers;
|
||||
// First handler for this address so we should register the connection
|
||||
var msg = { type : "register",
|
||||
address: address };
|
||||
sockJSConn.send(JSON.stringify(msg));
|
||||
} else {
|
||||
handlers[handlers.length] = handler;
|
||||
}
|
||||
}
|
||||
|
||||
that.unregisterHandler = function(address, handler) {
|
||||
checkSpecified("address", 'string', address);
|
||||
checkSpecified("handler", 'function', handler);
|
||||
checkOpen();
|
||||
var handlers = handlerMap[address];
|
||||
if (handlers) {
|
||||
var idx = handlers.indexOf(handler);
|
||||
if (idx != -1) handlers.splice(idx, 1);
|
||||
if (handlers.length == 0) {
|
||||
// No more local handlers so we should unregister the connection
|
||||
|
||||
var msg = { type : "unregister",
|
||||
address: address};
|
||||
sockJSConn.send(JSON.stringify(msg));
|
||||
delete handlerMap[address];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
that.close = function() {
|
||||
checkOpen();
|
||||
state = vertx.EventBus.CLOSING;
|
||||
sockJSConn.close();
|
||||
}
|
||||
|
||||
that.readyState = function() {
|
||||
return state;
|
||||
}
|
||||
|
||||
sockJSConn.onopen = function() {
|
||||
// Send the first ping then send a ping every pingInterval milliseconds
|
||||
sendPing();
|
||||
pingTimerID = setInterval(sendPing, pingInterval);
|
||||
state = vertx.EventBus.OPEN;
|
||||
if (that.onopen) {
|
||||
that.onopen();
|
||||
}
|
||||
};
|
||||
|
||||
sockJSConn.onclose = function() {
|
||||
state = vertx.EventBus.CLOSED;
|
||||
if (pingTimerID) clearInterval(pingTimerID);
|
||||
if (that.onclose) {
|
||||
that.onclose();
|
||||
}
|
||||
};
|
||||
|
||||
sockJSConn.onmessage = function(e) {
|
||||
var msg = e.data;
|
||||
var json = JSON.parse(msg);
|
||||
var type = json.type;
|
||||
if (type === 'err') {
|
||||
console.error("Error received on connection: " + json.body);
|
||||
return;
|
||||
}
|
||||
var body = json.body;
|
||||
var replyAddress = json.replyAddress;
|
||||
var address = json.address;
|
||||
var replyHandler;
|
||||
if (replyAddress) {
|
||||
replyHandler = function(reply, replyHandler) {
|
||||
// Send back reply
|
||||
that.send(replyAddress, reply, replyHandler);
|
||||
};
|
||||
}
|
||||
var handlers = handlerMap[address];
|
||||
if (handlers) {
|
||||
// We make a copy since the handler might get unregistered from within the
|
||||
// handler itself, which would screw up our iteration
|
||||
var copy = handlers.slice(0);
|
||||
for (var i = 0; i < copy.length; i++) {
|
||||
copy[i](body, replyHandler);
|
||||
}
|
||||
} else {
|
||||
// Might be a reply message
|
||||
var handler = replyHandlers[address];
|
||||
if (handler) {
|
||||
delete replyHandlers[address];
|
||||
handler(body, replyHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function sendPing() {
|
||||
var msg = {
|
||||
type: "ping"
|
||||
}
|
||||
sockJSConn.send(JSON.stringify(msg));
|
||||
}
|
||||
|
||||
function sendOrPub(sendOrPub, address, message, replyHandler) {
|
||||
checkSpecified("address", 'string', address);
|
||||
checkSpecified("replyHandler", 'function', replyHandler, true);
|
||||
checkOpen();
|
||||
var envelope = { type : sendOrPub,
|
||||
address: address,
|
||||
body: message };
|
||||
if (replyHandler) {
|
||||
var replyAddress = makeUUID();
|
||||
envelope.replyAddress = replyAddress;
|
||||
replyHandlers[replyAddress] = replyHandler;
|
||||
}
|
||||
var str = JSON.stringify(envelope);
|
||||
sockJSConn.send(str);
|
||||
}
|
||||
|
||||
function checkOpen() {
|
||||
if (state != vertx.EventBus.OPEN) {
|
||||
throw new Error('INVALID_STATE_ERR');
|
||||
}
|
||||
}
|
||||
|
||||
function checkSpecified(paramName, paramType, param, optional) {
|
||||
if (!optional && !param) {
|
||||
throw new Error("Parameter " + paramName + " must be specified");
|
||||
}
|
||||
if (param && typeof param != paramType) {
|
||||
throw new Error("Parameter " + paramName + " must be of type " + paramType);
|
||||
}
|
||||
}
|
||||
|
||||
function isFunction(obj) {
|
||||
return !!(obj && obj.constructor && obj.call && obj.apply);
|
||||
}
|
||||
|
||||
function makeUUID(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
|
||||
.replace(/[xy]/g,function(a,b){return b=Math.random()*16,(a=="y"?b&3|8:b|0).toString(16)})}
|
||||
|
||||
}
|
||||
|
||||
vertx.EventBus.CONNECTING = 0;
|
||||
vertx.EventBus.OPEN = 1;
|
||||
vertx.EventBus.CLOSING = 2;
|
||||
vertx.EventBus.CLOSED = 3;
|
||||
|
||||
return vertx.EventBus;
|
||||
|
||||
});
|
@ -1 +0,0 @@
|
||||
JAVA_OPTS="-Dconfig.file=${{chdir}}/conf/application.conf $JAVA_OPTS"
|
@ -1,8 +0,0 @@
|
||||
|
||||
1. Install httpie (https://github.com/jkbr/httpie)
|
||||
|
||||
sudo apt-get install python-setuptools
|
||||
sudo easy_install httpie
|
||||
|
||||
2. Send messages stored in messages/ directory
|
||||
e.g. http POST 192.168.22.146:8989/meeting < create-meeting.json
|
@ -1,49 +0,0 @@
|
||||
{
|
||||
"header": {
|
||||
"destination": {
|
||||
"to": "apps_channel"
|
||||
},
|
||||
"reply": {
|
||||
"to": "apps_channel",
|
||||
"correlation_id": "abc"
|
||||
},
|
||||
"name": "create_meeting_request",
|
||||
"timestamp": "2013-12-23T08:50Z",
|
||||
"source": "web-api"
|
||||
},
|
||||
"payload": {
|
||||
"meeting_descriptor": {
|
||||
"name": "English 101",
|
||||
"external_id": "english_101",
|
||||
"record": true,
|
||||
"welcome_message": "Welcome to English 101",
|
||||
"logout_url": "http://www.bigbluebutton.org",
|
||||
"avatar_url": "http://www.gravatar.com/bigbluebutton",
|
||||
"max_users": 20,
|
||||
"duration": {
|
||||
"length": 120,
|
||||
"allow_extend": false,
|
||||
"max": 240
|
||||
},
|
||||
"voice_conference": {
|
||||
"pin": 123456,
|
||||
"number": 85115
|
||||
},
|
||||
"phone_numbers": [
|
||||
{
|
||||
"number": "613-520-7600",
|
||||
"description": "Ottawa"
|
||||
},
|
||||
{
|
||||
"number": "1-888-555-7890",
|
||||
"description": "NA Toll-Free"
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"customer_id": "acme-customer",
|
||||
"customer_name": "ACME"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,30 +0,0 @@
|
||||
{
|
||||
"header": {
|
||||
"destination": {
|
||||
"to": "apps_channel"
|
||||
},
|
||||
"reply": {
|
||||
"to": "apps_channel",
|
||||
"correlation_id": "abc"
|
||||
},
|
||||
"name": "register_user_request",
|
||||
"timestamp": "2013-12-23T08:50Z",
|
||||
"source": "bbb-web"
|
||||
},
|
||||
"payload": {
|
||||
"meeting": {
|
||||
"name": "English 101",
|
||||
"id": "english_101"
|
||||
},
|
||||
"session": "english_101-12345",
|
||||
"user_descriptor": {
|
||||
"external_id": "user1",
|
||||
"name": "Guga",
|
||||
"role": "MODERATOR",
|
||||
"pin": 12345,
|
||||
"welcome_message": "Welcome to English 101",
|
||||
"logout_url": "http://www.example.com",
|
||||
"avatar_url": "http://www.example.com/avatar.png"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
akka {
|
||||
actor {
|
||||
debug {
|
||||
# enable DEBUG logging of all AutoReceiveMessages (Kill, PoisonPill et.c.)
|
||||
autoreceive = on
|
||||
# enable DEBUG logging of actor lifecycle changes
|
||||
lifecycle = on
|
||||
}
|
||||
}
|
||||
loggers = ["akka.event.slf4j.Slf4jLogger"]
|
||||
loglevel = "DEBUG"
|
||||
|
||||
rediscala-publish-worker-dispatcher {
|
||||
mailbox-type = "akka.dispatch.SingleConsumerOnlyUnboundedMailbox"
|
||||
# Throughput defines the maximum number of messages to be
|
||||
# processed per actor before the thread jumps to the next actor.
|
||||
# Set to 1 for as fair as possible.
|
||||
throughput = 512
|
||||
}
|
||||
|
||||
rediscala-subscriber-worker-dispatcher {
|
||||
mailbox-type = "akka.dispatch.SingleConsumerOnlyUnboundedMailbox"
|
||||
# Throughput defines the maximum number of messages to be
|
||||
# processed per actor before the thread jumps to the next actor.
|
||||
# Set to 1 for as fair as possible.
|
||||
throughput = 512
|
||||
}
|
||||
}
|
||||
|
||||
redis {
|
||||
host="127.0.0.1"
|
||||
port=6379
|
||||
password=""
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
# #################################
|
||||
# ##### Default configuration #####
|
||||
# #################################
|
||||
|
||||
# Available replacements
|
||||
# ------------------------------------------------
|
||||
# ${{author}} debian author
|
||||
# ${{descr}} debian package description
|
||||
# ${{exec}} startup script name
|
||||
# ${{chdir}} app directory
|
||||
# ${{retries}} retries for startup
|
||||
# ${{retryTimeout}} retry timeout
|
||||
# ${{app_name}} normalized app name
|
||||
# ${{daemon_user}} daemon user
|
||||
# -------------------------------------------------
|
||||
# DEPRECATED, use -J-Xmx1024m instead
|
||||
# -mem 1024
|
||||
|
||||
# Setting -X directly (-J is stripped)
|
||||
# -J-X
|
||||
# -J-Xmx1024
|
||||
|
||||
# Add additional jvm parameters
|
||||
# -Dkey=val
|
||||
|
||||
# For play applications you may set
|
||||
# -Dpidfile.path=/var/run/${{app_name}}/play.pid
|
||||
|
||||
# Turn on JVM debugging, open at the given port
|
||||
# -jvm-debug <port>
|
||||
|
||||
# Don't run the java version check
|
||||
# -no-version-check
|
||||
|
||||
-J-Xms130m
|
||||
-J-Xmx256m
|
||||
|
||||
# With universal:packageBin:
|
||||
# - setup with a configuration tool after unzip
|
||||
# - use the path to the application.ini file
|
||||
# -Dconfig.file=${{path_to}}/conf/application.conf
|
||||
|
@ -1,28 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%date{ISO8601} %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<File>logs/bbb-vertx-akka.log</File>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<FileNamePattern>logs/bbb-vertx-akka.%d{yyyy-MM-dd}.log</FileNamePattern>
|
||||
<!-- keep 30 days worth of history -->
|
||||
<MaxHistory>5</MaxHistory>
|
||||
</rollingPolicy>
|
||||
<layout class="ch.qos.logback.classic.PatternLayout">
|
||||
<Pattern>%d{"yyyy-MM-dd HH:mm:ss,SSSXXX"} [%thread] %-5level %logger{35} - %msg%n</Pattern>
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<logger name="akka" level="INFO" />
|
||||
<logger name="org.bigbluebutton" level="DEBUG" />
|
||||
|
||||
<root level="DEBUG">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
<appender-ref ref="FILE" />
|
||||
</root>
|
||||
</configuration>
|
Loading…
Reference in New Issue
Block a user