Merge pull request #15288 from antobinary/cleanup2

chore: cleanup of vertx-akka
This commit is contained in:
Anton Georgiev 2022-06-29 10:43:47 -04:00 committed by GitHub
commit b7e1cc3a54
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
96 changed files with 0 additions and 4388 deletions

View File

@ -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/

View File

@ -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

View File

@ -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")

View File

@ -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

View File

@ -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;
}
}

View File

@ -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>

View File

@ -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>

View File

@ -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;
});

View File

@ -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
}

View File

@ -1 +0,0 @@
sbt.version=1.2.7

View File

@ -1 +0,0 @@

View File

@ -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")

View File

@ -1,6 +0,0 @@
#!/usr/bin/env bash
rm -rf src/main/resources
cp -R src/universal/conf src/main/resources
sbt run

View File

@ -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.

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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();
}

View File

@ -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";
}
}

View File

@ -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";
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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";
}
}

View File

@ -1,8 +0,0 @@
package org.bigbluebutton.red5.client.messaging;
public class DisconnectAllMessage implements ClientMessage {
public String getMessageName() {
return "DisconnectAllMessage";
}
}

View File

@ -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";
}
}

View File

@ -1,6 +0,0 @@
package org.bigbluebutton.red5.client.messaging;
public interface IConnectionInvokerService {
void sendMessage(final ClientMessage message);
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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));
}
}

View File

@ -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());
});
}
}

View File

@ -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());
}
}

View File

@ -1,6 +0,0 @@
package org.bigbluebutton.vertx;
public interface IAkkaToVertxGateway {
void send(String json);
}

View File

@ -1,6 +0,0 @@
package org.bigbluebutton.vertx;
public interface IVertxToAkkaGateway {
void send(String json);
}

View File

@ -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)));
}
});
}
}

View File

@ -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());
}
}

View File

@ -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!"));
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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());
}
}

View File

@ -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());
}
});
}
}

View File

@ -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 ")
}
}

View File

@ -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()
}

View File

@ -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()
}
}

View File

@ -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()))
}
}

View File

@ -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 ")
}
}

View File

@ -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 ")
}
}

View File

@ -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")
}
}

View File

@ -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("")
}

View File

@ -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())
}
}

View File

@ -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()
}
}

View File

@ -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()
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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))
}
}

View File

@ -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)
}
}

View File

@ -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))
}
}

View File

@ -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)
}
}
}

View File

@ -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")
}

View File

@ -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 events 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
}

View File

@ -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)
}
}

View File

@ -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())
}
}

View File

@ -1,8 +0,0 @@
package org.bigbluebutton.client.endpoint.redis
class MessageSender(publisher: RedisPublisher) {
def send(channel: String, data: String) {
publisher.publish(channel, data)
}
}

View File

@ -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))
}
}

View File

@ -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
)
}

View File

@ -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
}
}

View File

@ -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)
}

View File

@ -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)
}
}
}

View File

@ -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
}
}

View File

@ -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)
}
}

View File

@ -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)
}

View File

@ -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)
}
}
}
}

View File

@ -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
}
}

View File

@ -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>

View File

@ -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>

View File

@ -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;
});

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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;
});

View File

@ -1 +0,0 @@
JAVA_OPTS="-Dconfig.file=${{chdir}}/conf/application.conf $JAVA_OPTS"

View File

@ -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

View File

@ -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"
}
}
}
}

View File

@ -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"
}
}
}

View File

@ -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=""
}

View File

@ -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

View File

@ -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>