Make breakout rooms use the selected slide of the current presentation as default presentation.
This commit is contained in:
parent
87b4b8ca07
commit
0e72d7523d
@ -43,7 +43,6 @@ http {
|
|||||||
services {
|
services {
|
||||||
bbbWebAPI = "http://192.168.23.33/bigbluebutton/api"
|
bbbWebAPI = "http://192.168.23.33/bigbluebutton/api"
|
||||||
sharedSecret = "changeme"
|
sharedSecret = "changeme"
|
||||||
defaultPresentationURL = "http://localhost/default.pdf"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
red5 {
|
red5 {
|
||||||
|
@ -18,7 +18,6 @@ trait SystemConfiguration {
|
|||||||
lazy val bbbWebSharedSecret = Try(config.getString("services.sharedSecret")).getOrElse("changeme")
|
lazy val bbbWebSharedSecret = Try(config.getString("services.sharedSecret")).getOrElse("changeme")
|
||||||
lazy val bbbWebModeratorPassword = Try(config.getString("services.moderatorPassword")).getOrElse("changeme")
|
lazy val bbbWebModeratorPassword = Try(config.getString("services.moderatorPassword")).getOrElse("changeme")
|
||||||
lazy val bbbWebViewerPassword = Try(config.getString("services.viewerPassword")).getOrElse("changeme")
|
lazy val bbbWebViewerPassword = Try(config.getString("services.viewerPassword")).getOrElse("changeme")
|
||||||
lazy val bbbWebDefaultPresentationURL = Try(config.getString("services.defaultPresentationURL")).getOrElse("changeme")
|
|
||||||
lazy val keysExpiresInSec = Try(config.getInt("redis.keyExpiry")).getOrElse(14 * 86400) // 14 days
|
lazy val keysExpiresInSec = Try(config.getInt("redis.keyExpiry")).getOrElse(14 * 86400) // 14 days
|
||||||
lazy val red5DeskShareIP = Try(config.getString("red5.deskshareip")).getOrElse("127.0.0.1")
|
lazy val red5DeskShareIP = Try(config.getString("red5.deskshareip")).getOrElse("127.0.0.1")
|
||||||
lazy val red5DeskShareApp = Try(config.getString("red5.deskshareapp")).getOrElse("")
|
lazy val red5DeskShareApp = Try(config.getString("red5.deskshareapp")).getOrElse("")
|
||||||
|
@ -94,7 +94,7 @@ class JsonMessageSenderActor(val service: MessageSender)
|
|||||||
private def handleCreateBreakoutRoom(msg: CreateBreakoutRoom) {
|
private def handleCreateBreakoutRoom(msg: CreateBreakoutRoom) {
|
||||||
val payload = new CreateBreakoutRoomRequestPayload(msg.room.breakoutId, msg.room.parentId, msg.room.name,
|
val payload = new CreateBreakoutRoomRequestPayload(msg.room.breakoutId, msg.room.parentId, msg.room.name,
|
||||||
msg.room.voiceConfId, msg.room.viewerPassword, msg.room.moderatorPassword,
|
msg.room.voiceConfId, msg.room.viewerPassword, msg.room.moderatorPassword,
|
||||||
msg.room.durationInMinutes, msg.room.defaultPresentationURL, msg.room.record)
|
msg.room.durationInMinutes, msg.room.sourcePresentationId, msg.room.sourcePresentationSlide, msg.room.record)
|
||||||
val request = new CreateBreakoutRoomRequest(payload)
|
val request = new CreateBreakoutRoomRequest(payload)
|
||||||
service.send(MessagingConstants.FROM_MEETING_CHANNEL, request.toJson())
|
service.send(MessagingConstants.FROM_MEETING_CHANNEL, request.toJson())
|
||||||
}
|
}
|
||||||
|
@ -117,7 +117,7 @@ class LiveMeeting(val mProps: MeetingProperties,
|
|||||||
meetingModel.meetingHasEnded
|
meetingModel.meetingHasEnded
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See if this meeting has breakout rooms. If so, we also need to end them.
|
* Check if this meeting has breakout rooms. If so, we also need to end them.
|
||||||
*/
|
*/
|
||||||
handleEndAllBreakoutRooms(new EndAllBreakoutRooms(msg.meetingId))
|
handleEndAllBreakoutRooms(new EndAllBreakoutRooms(msg.meetingId))
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ object UserMessagesProtocol extends DefaultJsonProtocol {
|
|||||||
implicit val inMsgHeaderFormat = jsonFormat1(InMessageHeader)
|
implicit val inMsgHeaderFormat = jsonFormat1(InMessageHeader)
|
||||||
implicit val outMsgHeaderFormat = jsonFormat1(OutMsgHeader)
|
implicit val outMsgHeaderFormat = jsonFormat1(OutMsgHeader)
|
||||||
implicit val outMsgEnvelopeHeaderFormat = jsonFormat2(OutMsgEnvelopeHeader)
|
implicit val outMsgEnvelopeHeaderFormat = jsonFormat2(OutMsgEnvelopeHeader)
|
||||||
implicit val createBreakoutRoomOutMsgPayloadFormat = jsonFormat8(CreateBreakoutRoomOutMsgPayload)
|
implicit val createBreakoutRoomOutMsgPayloadFormat = jsonFormat10(CreateBreakoutRoomOutMsgPayload)
|
||||||
implicit val createBreakoutRoomOutMsgEnvelopePayloadFormat = jsonFormat2(CreateBreakoutRoomOutMsgEnvelopePayload)
|
implicit val createBreakoutRoomOutMsgEnvelopePayloadFormat = jsonFormat2(CreateBreakoutRoomOutMsgEnvelopePayload)
|
||||||
implicit val createBreakoutRoomOutMsgEnvelopeFormat = jsonFormat2(CreateBreakoutRoomOutMsgEnvelope)
|
implicit val createBreakoutRoomOutMsgEnvelopeFormat = jsonFormat2(CreateBreakoutRoomOutMsgEnvelope)
|
||||||
|
|
||||||
|
@ -5,12 +5,10 @@ case class OutMsgEnvelopeHeader(`type`: MessageType.MessageType, address: String
|
|||||||
|
|
||||||
trait OutMessage
|
trait OutMessage
|
||||||
|
|
||||||
case class CreateBreakoutRoomOutMsgEnvelope(header: OutMsgEnvelopeHeader,
|
case class CreateBreakoutRoomOutMsgEnvelope(header: OutMsgEnvelopeHeader, payload: CreateBreakoutRoomOutMsgEnvelopePayload)
|
||||||
payload: CreateBreakoutRoomOutMsgEnvelopePayload)
|
case class CreateBreakoutRoomOutMsgEnvelopePayload(header: OutMsgHeader, payload: CreateBreakoutRoomOutMsgPayload)
|
||||||
case class CreateBreakoutRoomOutMsgEnvelopePayload(header: OutMsgHeader,
|
|
||||||
payload: CreateBreakoutRoomOutMsgPayload)
|
|
||||||
case class CreateBreakoutRoomOutMsgPayload(breakoutId: String, name: String, parentId: String,
|
case class CreateBreakoutRoomOutMsgPayload(breakoutId: String, name: String, parentId: String,
|
||||||
voiceConfId: String, durationInMinutes: Int,
|
voiceConfId: String, durationInMinutes: Int,
|
||||||
moderatorPassword: String, viewerPassword: String,
|
moderatorPassword: String, viewerPassword: String,
|
||||||
defaultPresentationUrl: String)
|
sourcePresentationId: String, sourcePresentationSlide: Int, record: Boolean)
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ case class CreateBreakoutRoom(meetingId: String, room: BreakoutRoomOutPayload) e
|
|||||||
case class EndBreakoutRoom(breakoutId: String) extends IOutMessage
|
case class EndBreakoutRoom(breakoutId: String) extends IOutMessage
|
||||||
case class BreakoutRoomOutPayload(breakoutId: String, name: String, parentId: String,
|
case class BreakoutRoomOutPayload(breakoutId: String, name: String, parentId: String,
|
||||||
voiceConfId: String, durationInMinutes: Int, moderatorPassword: String, viewerPassword: String,
|
voiceConfId: String, durationInMinutes: Int, moderatorPassword: String, viewerPassword: String,
|
||||||
defaultPresentationURL: String, record: Boolean)
|
sourcePresentationId: String, sourcePresentationSlide: Int, record: Boolean)
|
||||||
case class BreakoutRoomJoinURLOutMessage(meetingId: String, recorded: Boolean, breakoutId: String, userId: String, joinURL: String) extends IOutMessage
|
case class BreakoutRoomJoinURLOutMessage(meetingId: String, recorded: Boolean, breakoutId: String, userId: String, joinURL: String) extends IOutMessage
|
||||||
case class BreakoutRoomStartedOutMessage(meetingId: String, recorded: Boolean, breakout: BreakoutRoomBody) extends IOutMessage
|
case class BreakoutRoomStartedOutMessage(meetingId: String, recorded: Boolean, breakout: BreakoutRoomBody) extends IOutMessage
|
||||||
case class BreakoutRoomBody(name: String, breakoutId: String)
|
case class BreakoutRoomBody(name: String, breakoutId: String)
|
||||||
|
@ -20,15 +20,6 @@ trait BreakoutRoomApp extends SystemConfiguration {
|
|||||||
val outGW: OutMessageGateway
|
val outGW: OutMessageGateway
|
||||||
val eventBus: IncomingEventBus
|
val eventBus: IncomingEventBus
|
||||||
|
|
||||||
def getDefaultPresentationURL(): String = {
|
|
||||||
var presURL = bbbWebDefaultPresentationURL
|
|
||||||
val page = presModel.getCurrentPage()
|
|
||||||
page foreach { p =>
|
|
||||||
presURL = BreakoutRoomsUtil.fromSWFtoPDF(p.swfUri)
|
|
||||||
}
|
|
||||||
presURL
|
|
||||||
}
|
|
||||||
|
|
||||||
def handleBreakoutRoomsList(msg: BreakoutRoomsListMessage) {
|
def handleBreakoutRoomsList(msg: BreakoutRoomsListMessage) {
|
||||||
val breakoutRooms = breakoutModel.getRooms().toVector map { r => new BreakoutRoomBody(r.name, r.id) }
|
val breakoutRooms = breakoutModel.getRooms().toVector map { r => new BreakoutRoomBody(r.name, r.id) }
|
||||||
outGW.send(new BreakoutRoomsListOutMessage(mProps.meetingID, breakoutRooms, breakoutModel.pendingRoomsNumber == 0 && breakoutRooms.length > 0));
|
outGW.send(new BreakoutRoomsListOutMessage(mProps.meetingID, breakoutRooms, breakoutModel.pendingRoomsNumber == 0 && breakoutRooms.length > 0));
|
||||||
@ -40,17 +31,20 @@ trait BreakoutRoomApp extends SystemConfiguration {
|
|||||||
log.warning("CreateBreakoutRooms event received while {} are pending to be created for meeting {}", breakoutModel.pendingRoomsNumber, mProps.meetingID)
|
log.warning("CreateBreakoutRooms event received while {} are pending to be created for meeting {}", breakoutModel.pendingRoomsNumber, mProps.meetingID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var i = 0
|
var i = 0
|
||||||
|
val sourcePresentationId = presModel.getCurrentPresentation().get.id
|
||||||
|
val sourcePresentationSlide = presModel.getCurrentPage().get.num
|
||||||
breakoutModel.pendingRoomsNumber = msg.rooms.length;
|
breakoutModel.pendingRoomsNumber = msg.rooms.length;
|
||||||
|
|
||||||
for (room <- msg.rooms) {
|
for (room <- msg.rooms) {
|
||||||
i += 1
|
i += 1
|
||||||
val presURL = bbbWebDefaultPresentationURL
|
|
||||||
val breakoutMeetingId = BreakoutRoomsUtil.createMeetingId(mProps.meetingID, i)
|
val breakoutMeetingId = BreakoutRoomsUtil.createMeetingId(mProps.meetingID, i)
|
||||||
val voiceConfId = BreakoutRoomsUtil.createVoiceConfId(mProps.voiceBridge, i)
|
val voiceConfId = BreakoutRoomsUtil.createVoiceConfId(mProps.voiceBridge, i)
|
||||||
val r = breakoutModel.createBreakoutRoom(breakoutMeetingId, room.name, voiceConfId, room.users, presURL)
|
val r = breakoutModel.createBreakoutRoom(breakoutMeetingId, room.name, voiceConfId, room.users)
|
||||||
val p = new BreakoutRoomOutPayload(r.id, r.name, mProps.meetingID,
|
val p = new BreakoutRoomOutPayload(r.id, r.name, mProps.meetingID,
|
||||||
r.voiceConfId, msg.durationInMinutes, mProps.moderatorPass, mProps.viewerPass,
|
r.voiceConfId, msg.durationInMinutes, mProps.moderatorPass, mProps.viewerPass,
|
||||||
r.defaultPresentationURL, msg.record)
|
sourcePresentationId, sourcePresentationSlide, msg.record)
|
||||||
outGW.send(new CreateBreakoutRoom(mProps.meetingID, p))
|
outGW.send(new CreateBreakoutRoom(mProps.meetingID, p))
|
||||||
}
|
}
|
||||||
meetingModel.breakoutRoomsdurationInMinutes = msg.durationInMinutes;
|
meetingModel.breakoutRoomsdurationInMinutes = msg.durationInMinutes;
|
||||||
@ -85,7 +79,7 @@ trait BreakoutRoomApp extends SystemConfiguration {
|
|||||||
breakoutModel.getRooms().foreach { room =>
|
breakoutModel.getRooms().foreach { room =>
|
||||||
breakoutModel.getAssignedUsers(room.id) foreach { users =>
|
breakoutModel.getAssignedUsers(room.id) foreach { users =>
|
||||||
users.foreach { u =>
|
users.foreach { u =>
|
||||||
log.debug("## Sending Join URL for users: {}", u);
|
log.debug("Sending Join URL for users: {}", u);
|
||||||
sendJoinURL(u, room.id)
|
sendJoinURL(u, room.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import scala.collection.immutable.HashMap
|
|||||||
|
|
||||||
case class BreakoutUser(id: String, name: String)
|
case class BreakoutUser(id: String, name: String)
|
||||||
case class BreakoutRoom(id: String, name: String, voiceConfId: String,
|
case class BreakoutRoom(id: String, name: String, voiceConfId: String,
|
||||||
assignedUsers: Vector[String], users: Vector[BreakoutUser], defaultPresentationURL: String)
|
assignedUsers: Vector[String], users: Vector[BreakoutUser])
|
||||||
|
|
||||||
class BreakoutRoomModel {
|
class BreakoutRoomModel {
|
||||||
private var rooms = new collection.immutable.HashMap[String, BreakoutRoom]
|
private var rooms = new collection.immutable.HashMap[String, BreakoutRoom]
|
||||||
@ -22,8 +22,8 @@ class BreakoutRoomModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def createBreakoutRoom(id: String, name: String, voiceConfId: String,
|
def createBreakoutRoom(id: String, name: String, voiceConfId: String,
|
||||||
assignedUsers: Vector[String], defaultPresentationURL: String): BreakoutRoom = {
|
assignedUsers: Vector[String]): BreakoutRoom = {
|
||||||
val room = new BreakoutRoom(id, name, voiceConfId, assignedUsers, Vector(), defaultPresentationURL)
|
val room = new BreakoutRoom(id, name, voiceConfId, assignedUsers, Vector())
|
||||||
add(room)
|
add(room)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,16 +94,10 @@ trait PresentationApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def handleGotoSlide(msg: GotoSlide) {
|
def handleGotoSlide(msg: GotoSlide) {
|
||||||
// println("Received GotoSlide for meeting=[" + msg.meetingID + "] page=[" + msg.page + "]")
|
|
||||||
// println("*** Before change page ****")
|
|
||||||
// printPresentations
|
|
||||||
presModel.changePage(msg.page) foreach { page =>
|
presModel.changePage(msg.page) foreach { page =>
|
||||||
// println("Switching page for meeting=[" + msg.meetingID + "] page=[" + page.id + "]")
|
log.debug("Switching page for meeting=[{}] page=[{}]", msg.meetingID, page.num);
|
||||||
outGW.send(new GotoSlideOutMsg(mProps.meetingID, mProps.recorded, page))
|
outGW.send(new GotoSlideOutMsg(mProps.meetingID, mProps.recorded, page))
|
||||||
|
|
||||||
}
|
}
|
||||||
// println("*** After change page ****")
|
|
||||||
// printPresentations
|
|
||||||
|
|
||||||
usersModel.getCurrentPresenter() foreach { pres =>
|
usersModel.getCurrentPresenter() foreach { pres =>
|
||||||
handleStopPollRequest(StopPollRequest(mProps.meetingID, pres.userID))
|
handleStopPollRequest(StopPollRequest(mProps.meetingID, pres.userID))
|
||||||
|
@ -8,12 +8,15 @@ public class CreateBreakoutRoomRequestPayload {
|
|||||||
public final String viewerPassword;
|
public final String viewerPassword;
|
||||||
public final String moderatorPassword;
|
public final String moderatorPassword;
|
||||||
public final Integer durationInMinutes; // The duration of the breakout room
|
public final Integer durationInMinutes; // The duration of the breakout room
|
||||||
public final String defaultPresentationURL;
|
public final String sourcePresentationId;
|
||||||
|
public final Integer sourcePresentationSlide;
|
||||||
public final Boolean record;
|
public final Boolean record;
|
||||||
|
|
||||||
public CreateBreakoutRoomRequestPayload(String breakoutId, String parentId, String name,
|
public CreateBreakoutRoomRequestPayload(String breakoutId, String parentId,
|
||||||
String voiceConfId, String viewerPassword, String moderatorPassword,
|
String name, String voiceConfId, String viewerPassword,
|
||||||
Integer duration, String defaultPresentationURL, Boolean record) {
|
String moderatorPassword, Integer duration,
|
||||||
|
String sourcePresentationId, Integer sourcePresentationSlide,
|
||||||
|
Boolean record) {
|
||||||
this.breakoutId = breakoutId;
|
this.breakoutId = breakoutId;
|
||||||
this.parentId = parentId;
|
this.parentId = parentId;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
@ -21,7 +24,8 @@ public class CreateBreakoutRoomRequestPayload {
|
|||||||
this.viewerPassword = viewerPassword;
|
this.viewerPassword = viewerPassword;
|
||||||
this.moderatorPassword = moderatorPassword;
|
this.moderatorPassword = moderatorPassword;
|
||||||
this.durationInMinutes = duration;
|
this.durationInMinutes = duration;
|
||||||
this.defaultPresentationURL = defaultPresentationURL;
|
this.sourcePresentationId = sourcePresentationId;
|
||||||
|
this.sourcePresentationSlide = sourcePresentationSlide;
|
||||||
this.record = record;
|
this.record = record;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,19 +9,20 @@ import com.google.gson.Gson;
|
|||||||
public class CreateBreakoutRoomRequestTest {
|
public class CreateBreakoutRoomRequestTest {
|
||||||
@Test
|
@Test
|
||||||
public void testCreateBreakoutRoomRequest() {
|
public void testCreateBreakoutRoomRequest() {
|
||||||
String breakoutId = "abc123";
|
String breakoutId = "183f0bf3a0982a127bdb8161e0c44eb696b3e75c-1474984695664";
|
||||||
String parentId = "abc-123";
|
String parentId = "abc-123";
|
||||||
Integer durationInMinutes = 20;
|
Integer durationInMinutes = 20;
|
||||||
String name = "Breakout room 1";
|
String name = "Breakout room 1";
|
||||||
String voiceConfId = "851153";
|
String voiceConfId = "851153";
|
||||||
String viewerPassword = "vp";
|
String viewerPassword = "vp";
|
||||||
String moderatorPassword = "mp";
|
String moderatorPassword = "mp";
|
||||||
String defaultPresentationURL = "http://localhost/foo.pdf";
|
String sourcePresentationId = "d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1474984695907";
|
||||||
|
Integer sourePresentationSlide = 5;
|
||||||
Boolean record = false;
|
Boolean record = false;
|
||||||
|
|
||||||
CreateBreakoutRoomRequestPayload payload =
|
CreateBreakoutRoomRequestPayload payload =
|
||||||
new CreateBreakoutRoomRequestPayload(breakoutId, parentId, name, voiceConfId,
|
new CreateBreakoutRoomRequestPayload(breakoutId, parentId, name, voiceConfId,
|
||||||
viewerPassword, moderatorPassword, durationInMinutes, defaultPresentationURL, record);
|
viewerPassword, moderatorPassword, durationInMinutes, sourcePresentationId, sourePresentationSlide, record);
|
||||||
CreateBreakoutRoomRequest msg = new CreateBreakoutRoomRequest(payload);
|
CreateBreakoutRoomRequest msg = new CreateBreakoutRoomRequest(payload);
|
||||||
Gson gson = new Gson();
|
Gson gson = new Gson();
|
||||||
String json = gson.toJson(msg);
|
String json = gson.toJson(msg);
|
||||||
@ -36,7 +37,8 @@ public class CreateBreakoutRoomRequestTest {
|
|||||||
Assert.assertEquals(rxMsg.payload.viewerPassword, viewerPassword);
|
Assert.assertEquals(rxMsg.payload.viewerPassword, viewerPassword);
|
||||||
Assert.assertEquals(rxMsg.payload.moderatorPassword, moderatorPassword);
|
Assert.assertEquals(rxMsg.payload.moderatorPassword, moderatorPassword);
|
||||||
Assert.assertEquals(rxMsg.payload.durationInMinutes, durationInMinutes);
|
Assert.assertEquals(rxMsg.payload.durationInMinutes, durationInMinutes);
|
||||||
Assert.assertEquals(rxMsg.payload.defaultPresentationURL, defaultPresentationURL);
|
Assert.assertEquals(rxMsg.payload.sourcePresentationId, sourcePresentationId);
|
||||||
|
Assert.assertEquals(rxMsg.payload.sourcePresentationSlide, sourePresentationSlide);
|
||||||
Assert.assertEquals(rxMsg.payload.record, record);
|
Assert.assertEquals(rxMsg.payload.record, record);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,6 +59,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
|||||||
<bean id="presDownloadService" class="org.bigbluebutton.presentation.PresentationUrlDownloadService">
|
<bean id="presDownloadService" class="org.bigbluebutton.presentation.PresentationUrlDownloadService">
|
||||||
<property name="presentationDir" value="${presentationDir}"/>
|
<property name="presentationDir" value="${presentationDir}"/>
|
||||||
<property name="presentationBaseURL" value="${presentationBaseURL}"/>
|
<property name="presentationBaseURL" value="${presentationBaseURL}"/>
|
||||||
|
<property name="pageExtractor" ref="pageExtractor"/>
|
||||||
<property name="documentConversionService" ref="documentConversionService"/>
|
<property name="documentConversionService" ref="documentConversionService"/>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
@ -113,7 +113,8 @@ public class MeetingService implements MessageListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void registerUser(String meetingID, String internalUserId,
|
public void registerUser(String meetingID, String internalUserId,
|
||||||
String fullname, String role, String externUserID, String authToken, String avatarURL) {
|
String fullname, String role, String externUserID,
|
||||||
|
String authToken, String avatarURL) {
|
||||||
handle(new RegisterUser(meetingID, internalUserId, fullname, role,
|
handle(new RegisterUser(meetingID, internalUserId, fullname, role,
|
||||||
externUserID, authToken, avatarURL));
|
externUserID, authToken, avatarURL));
|
||||||
}
|
}
|
||||||
@ -142,19 +143,22 @@ public class MeetingService implements MessageListener {
|
|||||||
* Remove registered users who did not successfully joined the meeting.
|
* Remove registered users who did not successfully joined the meeting.
|
||||||
*/
|
*/
|
||||||
public void purgeRegisteredUsers() {
|
public void purgeRegisteredUsers() {
|
||||||
for (AbstractMap.Entry<String, Meeting> entry : this.meetings.entrySet()) {
|
for (AbstractMap.Entry<String, Meeting> entry : this.meetings
|
||||||
|
.entrySet()) {
|
||||||
Long now = System.nanoTime();
|
Long now = System.nanoTime();
|
||||||
Meeting meeting = entry.getValue();
|
Meeting meeting = entry.getValue();
|
||||||
|
|
||||||
ConcurrentMap<String, User> users = meeting.getUsersMap();
|
ConcurrentMap<String, User> users = meeting.getUsersMap();
|
||||||
|
|
||||||
for (AbstractMap.Entry<String, Long> registeredUser : meeting.getRegisteredUsers().entrySet()) {
|
for (AbstractMap.Entry<String, Long> registeredUser : meeting
|
||||||
|
.getRegisteredUsers().entrySet()) {
|
||||||
String registeredUserID = registeredUser.getKey();
|
String registeredUserID = registeredUser.getKey();
|
||||||
Long registeredUserDate = registeredUser.getValue();
|
Long registeredUserDate = registeredUser.getValue();
|
||||||
|
|
||||||
long registrationTime = registeredUserDate.longValue();
|
long registrationTime = registeredUserDate.longValue();
|
||||||
long elapsedTime = now - registrationTime;
|
long elapsedTime = now - registrationTime;
|
||||||
if ( elapsedTime >= 60000 && !users.containsKey(registeredUserID)) {
|
if (elapsedTime >= 60000
|
||||||
|
&& !users.containsKey(registeredUserID)) {
|
||||||
meeting.userUnregistered(registeredUserID);
|
meeting.userUnregistered(registeredUserID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -319,7 +323,8 @@ public class MeetingService implements MessageListener {
|
|||||||
m.getName(), m.isRecord(), m.getTelVoice(), m.getDuration(),
|
m.getName(), m.isRecord(), m.getTelVoice(), m.getDuration(),
|
||||||
m.getAutoStartRecording(), m.getAllowStartStopRecording(),
|
m.getAutoStartRecording(), m.getAllowStartStopRecording(),
|
||||||
m.getModeratorPassword(), m.getViewerPassword(),
|
m.getModeratorPassword(), m.getViewerPassword(),
|
||||||
m.getCreateTime(), formatPrettyDate(m.getCreateTime()), m.isBreakout());
|
m.getCreateTime(), formatPrettyDate(m.getCreateTime()),
|
||||||
|
m.isBreakout());
|
||||||
}
|
}
|
||||||
|
|
||||||
private String formatPrettyDate(Long timestamp) {
|
private String formatPrettyDate(Long timestamp) {
|
||||||
@ -357,8 +362,10 @@ public class MeetingService implements MessageListener {
|
|||||||
int dashes = meetingId.split("-", -1).length - 1;
|
int dashes = meetingId.split("-", -1).length - 1;
|
||||||
for (String key : meetings.keySet()) {
|
for (String key : meetings.keySet()) {
|
||||||
int keyDashes = key.split("-", -1).length - 1;
|
int keyDashes = key.split("-", -1).length - 1;
|
||||||
if (dashes == 2 && key.equals(meetingId)
|
if (dashes == 2
|
||||||
|| (dashes < 2 && keyDashes < 2 && key.startsWith(meetingId))) {
|
&& key.equals(meetingId)
|
||||||
|
|| (dashes < 2 && keyDashes < 2 && key
|
||||||
|
.startsWith(meetingId))) {
|
||||||
return (Meeting) meetings.get(key);
|
return (Meeting) meetings.get(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -484,7 +491,8 @@ public class MeetingService implements MessageListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateRecordings(List<String> idList, Map<String, String> metaParams) {
|
public void updateRecordings(List<String> idList,
|
||||||
|
Map<String, String> metaParams) {
|
||||||
recordingService.updateMetaParams(idList, metaParams);
|
recordingService.updateMetaParams(idList, metaParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -527,12 +535,14 @@ public class MeetingService implements MessageListener {
|
|||||||
params.put("voiceBridge", message.voiceConfId);
|
params.put("voiceBridge", message.voiceConfId);
|
||||||
params.put("duration", message.durationInMinutes.toString());
|
params.put("duration", message.durationInMinutes.toString());
|
||||||
params.put("record", message.record.toString());
|
params.put("record", message.record.toString());
|
||||||
params.put("welcome", getMeeting(message.parentId).getWelcomeMessageTemplate());
|
params.put("welcome", getMeeting(message.parentId)
|
||||||
|
.getWelcomeMessageTemplate());
|
||||||
|
|
||||||
Map<String, String> parentMeetingMetadata = parentMeeting.getMetadata();
|
Map<String, String> parentMeetingMetadata = parentMeeting
|
||||||
|
.getMetadata();
|
||||||
|
|
||||||
String metaPrefix = "meta_";
|
String metaPrefix = "meta_";
|
||||||
for (String key: parentMeetingMetadata.keySet()) {
|
for (String key : parentMeetingMetadata.keySet()) {
|
||||||
String metaName = metaPrefix + key;
|
String metaName = metaPrefix + key;
|
||||||
// Inject metadata from parent meeting into the breakout room.
|
// Inject metadata from parent meeting into the breakout room.
|
||||||
params.put(metaName, parentMeetingMetadata.get(key));
|
params.put(metaName, parentMeetingMetadata.get(key));
|
||||||
@ -542,10 +552,12 @@ public class MeetingService implements MessageListener {
|
|||||||
|
|
||||||
handleCreateMeeting(breakout);
|
handleCreateMeeting(breakout);
|
||||||
|
|
||||||
presDownloadService.downloadAndProcessDocument(
|
presDownloadService.extractPage(message.parentId,
|
||||||
message.defaultPresentationURL, breakout.getInternalId());
|
message.sourcePresentationId,
|
||||||
|
message.sourcePresentationSlide, breakout.getInternalId());
|
||||||
} else {
|
} else {
|
||||||
log.error("Failed to create breakout room " + message.breakoutId + ". Parent meeting not found.");
|
log.error("Failed to create breakout room " + message.breakoutId
|
||||||
|
+ ".Reason: Parent meeting not found.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -595,6 +607,8 @@ public class MeetingService implements MessageListener {
|
|||||||
|
|
||||||
Gson gson = new Gson();
|
Gson gson = new Gson();
|
||||||
String logStr = gson.toJson(logData);
|
String logStr = gson.toJson(logData);
|
||||||
|
|
||||||
|
log.info("Meeting restarted: data={}", logStr);
|
||||||
} else {
|
} else {
|
||||||
Map<String, Object> logData = new HashMap<String, Object>();
|
Map<String, Object> logData = new HashMap<String, Object>();
|
||||||
logData.put("meetingId", m.getInternalId());
|
logData.put("meetingId", m.getInternalId());
|
||||||
@ -742,7 +756,7 @@ public class MeetingService implements MessageListener {
|
|||||||
Meeting m = getMeeting(message.meetingId);
|
Meeting m = getMeeting(message.meetingId);
|
||||||
if (m != null) {
|
if (m != null) {
|
||||||
User user = m.getUserById(message.userId);
|
User user = m.getUserById(message.userId);
|
||||||
if(user != null){
|
if (user != null) {
|
||||||
user.setStatus(message.status, message.value);
|
user.setStatus(message.status, message.value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -750,36 +764,38 @@ public class MeetingService implements MessageListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(IMessage message) {
|
public void handle(IMessage message) {
|
||||||
receivedMessages.add(message);
|
receivedMessages.add(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setParamsProcessorUtil(ParamsProcessorUtil util) {
|
public void setParamsProcessorUtil(ParamsProcessorUtil util) {
|
||||||
this.paramsProcessorUtil = util;
|
this.paramsProcessorUtil = util;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPresDownloadService(PresentationUrlDownloadService presDownloadService) {
|
public void setPresDownloadService(
|
||||||
|
PresentationUrlDownloadService presDownloadService) {
|
||||||
this.presDownloadService = presDownloadService;
|
this.presDownloadService = presDownloadService;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processStunTurnInfoRequested (StunTurnInfoRequested message) {
|
private void processStunTurnInfoRequested(StunTurnInfoRequested message) {
|
||||||
Set<StunServer> stuns = stunTurnService.getStunServers();
|
Set<StunServer> stuns = stunTurnService.getStunServers();
|
||||||
log.info("\nhere are the stuns:");
|
log.info("\nhere are the stuns:");
|
||||||
for(StunServer s : stuns) {
|
for (StunServer s : stuns) {
|
||||||
log.info("a stun: " + s.url);
|
log.info("a stun: " + s.url);
|
||||||
}
|
}
|
||||||
Set<TurnEntry> turns = stunTurnService.getStunAndTurnServersFor(message.internalUserId);
|
Set<TurnEntry> turns = stunTurnService
|
||||||
log.info("\nhere are the (" + turns.size() +") turns for internalUserId:" + message.internalUserId);
|
.getStunAndTurnServersFor(message.internalUserId);
|
||||||
for(TurnEntry t : turns) {
|
log.info("\nhere are the (" + turns.size()
|
||||||
log.info("a turn: " + t.url + "username/pass=" + t.username + '/' + t.password);
|
+ ") turns for internalUserId:" + message.internalUserId);
|
||||||
|
for (TurnEntry t : turns) {
|
||||||
|
log.info("a turn: " + t.url + "username/pass=" + t.username + '/'
|
||||||
|
+ t.password);
|
||||||
}
|
}
|
||||||
messagingService.sendStunTurnInfo(message.meetingId, message.internalUserId, stuns, turns);
|
messagingService.sendStunTurnInfo(message.meetingId,
|
||||||
|
message.internalUserId, stuns, turns);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void userJoinedVoice(UserJoinedVoice message) {
|
public void userJoinedVoice(UserJoinedVoice message) {
|
||||||
Meeting m = getMeeting(message.meetingId);
|
Meeting m = getMeeting(message.meetingId);
|
||||||
if (m != null) {
|
if (m != null) {
|
||||||
@ -886,7 +902,6 @@ public class MeetingService implements MessageListener {
|
|||||||
runExec.execute(task);
|
runExec.execute(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void start() {
|
public void start() {
|
||||||
log.info("Starting Meeting Service.");
|
log.info("Starting Meeting Service.");
|
||||||
try {
|
try {
|
||||||
@ -936,7 +951,8 @@ public class MeetingService implements MessageListener {
|
|||||||
messagingService = mess;
|
messagingService = mess;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setExpiredMeetingCleanupTimerTask(ExpiredMeetingCleanupTimerTask c) {
|
public void setExpiredMeetingCleanupTimerTask(
|
||||||
|
ExpiredMeetingCleanupTimerTask c) {
|
||||||
cleaner = c;
|
cleaner = c;
|
||||||
cleaner.setMeetingService(this);
|
cleaner.setMeetingService(this);
|
||||||
cleaner.start();
|
cleaner.start();
|
||||||
@ -946,11 +962,14 @@ public class MeetingService implements MessageListener {
|
|||||||
removeMeetingWhenEnded = s;
|
removeMeetingWhenEnded = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRegisteredUserCleanupTimerTask(RegisteredUserCleanupTimerTask c) {
|
public void setRegisteredUserCleanupTimerTask(
|
||||||
|
RegisteredUserCleanupTimerTask c) {
|
||||||
registeredUserCleaner = c;
|
registeredUserCleaner = c;
|
||||||
registeredUserCleaner.setMeetingService(this);
|
registeredUserCleaner.setMeetingService(this);
|
||||||
registeredUserCleaner.start();
|
registeredUserCleaner.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStunTurnService(StunTurnService s) { stunTurnService = s; }
|
public void setStunTurnService(StunTurnService s) {
|
||||||
|
stunTurnService = s;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,8 @@ public class MeetingMessageHandler implements MessageHandler {
|
|||||||
msg.payload.viewerPassword,
|
msg.payload.viewerPassword,
|
||||||
msg.payload.moderatorPassword,
|
msg.payload.moderatorPassword,
|
||||||
msg.payload.durationInMinutes,
|
msg.payload.durationInMinutes,
|
||||||
msg.payload.defaultPresentationURL,
|
msg.payload.sourcePresentationId,
|
||||||
|
msg.payload.sourcePresentationSlide,
|
||||||
msg.payload.record
|
msg.payload.record
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -9,13 +9,15 @@ public class CreateBreakoutRoom implements IMessage {
|
|||||||
public final String viewerPassword;
|
public final String viewerPassword;
|
||||||
public final String moderatorPassword;
|
public final String moderatorPassword;
|
||||||
public final Integer durationInMinutes; // The duration of the breakout room
|
public final Integer durationInMinutes; // The duration of the breakout room
|
||||||
public final String defaultPresentationURL;
|
public final String sourcePresentationId;
|
||||||
|
public final Integer sourcePresentationSlide;
|
||||||
public final Boolean record;
|
public final Boolean record;
|
||||||
|
|
||||||
public CreateBreakoutRoom(String breakoutId, String parentId, String name,
|
public CreateBreakoutRoom(String breakoutId, String parentId, String name,
|
||||||
String voiceConfId, String viewerPassword,
|
String voiceConfId, String viewerPassword,
|
||||||
String moderatorPassword, Integer duration,
|
String moderatorPassword, Integer duration,
|
||||||
String defaultPresentationURL, Boolean record) {
|
String sourcePresentationId, Integer sourcePresentationSlide,
|
||||||
|
Boolean record) {
|
||||||
this.breakoutId = breakoutId;
|
this.breakoutId = breakoutId;
|
||||||
this.parentId = parentId;
|
this.parentId = parentId;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
@ -23,7 +25,8 @@ public class CreateBreakoutRoom implements IMessage {
|
|||||||
this.viewerPassword = viewerPassword;
|
this.viewerPassword = viewerPassword;
|
||||||
this.moderatorPassword = moderatorPassword;
|
this.moderatorPassword = moderatorPassword;
|
||||||
this.durationInMinutes = duration;
|
this.durationInMinutes = duration;
|
||||||
this.defaultPresentationURL = defaultPresentationURL;
|
this.sourcePresentationId = sourcePresentationId;
|
||||||
|
this.sourcePresentationSlide = sourcePresentationSlide;
|
||||||
this.record = record;
|
this.record = record;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,18 @@
|
|||||||
package org.bigbluebutton.presentation;
|
package org.bigbluebutton.presentation;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.FilenameFilter;
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.Timer;
|
|
||||||
|
|
||||||
import org.apache.commons.codec.digest.DigestUtils;
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
import org.apache.commons.httpclient.HttpClient;
|
import org.apache.commons.io.FilenameUtils;
|
||||||
import org.apache.commons.httpclient.HttpException;
|
|
||||||
import org.apache.commons.httpclient.HttpStatus;
|
|
||||||
import org.apache.commons.httpclient.methods.GetMethod;
|
|
||||||
import org.apache.commons.io.FileUtils;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public class PresentationUrlDownloadService {
|
public class PresentationUrlDownloadService {
|
||||||
private static Logger log = LoggerFactory.getLogger(PresentationUrlDownloadService.class);
|
private static Logger log = LoggerFactory
|
||||||
|
.getLogger(PresentationUrlDownloadService.class);
|
||||||
|
|
||||||
private final int maxRedirects = 5;
|
private PageExtractor pageExtractor;
|
||||||
private DocumentConversionService documentConversionService;
|
private DocumentConversionService documentConversionService;
|
||||||
private String presentationBaseURL;
|
private String presentationBaseURL;
|
||||||
private String presentationDir;
|
private String presentationDir;
|
||||||
@ -28,31 +21,53 @@ public class PresentationUrlDownloadService {
|
|||||||
documentConversionService.processDocument(uploadedPres);
|
documentConversionService.processDocument(uploadedPres);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void processUploadedFile(String meetingId, String presId, String filename, File presFile) {
|
public void processUploadedFile(String meetingId, String presId,
|
||||||
UploadedPresentation uploadedPres = new UploadedPresentation(meetingId, presId, filename, presentationBaseURL);
|
String filename, File presFile) {
|
||||||
|
UploadedPresentation uploadedPres = new UploadedPresentation(meetingId,
|
||||||
|
presId, filename, presentationBaseURL);
|
||||||
uploadedPres.setUploadedFile(presFile);
|
uploadedPres.setUploadedFile(presFile);
|
||||||
processUploadedPresentation(uploadedPres);
|
processUploadedPresentation(uploadedPres);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void downloadAndProcessDocument(String address, String meetingId) {
|
public void extractPage(String sourceMeetingId, String presentationId,
|
||||||
log.debug("downloadAndProcessDocument [pres=" + address + ", meeting=" + meetingId + "]");
|
Integer presentationSlide, String destinationMeetingId) {
|
||||||
|
|
||||||
String presFilename = address.substring(address.lastIndexOf('/') + 1);
|
// Construct the source meeting path
|
||||||
log.debug("downloadAndProcessDocument [filename=" + presFilename + "]");
|
File sourceMeetingPath = new File(presentationDir + File.separator
|
||||||
String filenameExt = getFilenameExt(presFilename);
|
+ sourceMeetingId + File.separator + sourceMeetingId
|
||||||
|
+ File.separator + presentationId);
|
||||||
|
|
||||||
String presId = generatePresentationId(presFilename);
|
final String presentationFilter = presentationId;
|
||||||
File uploadDir = createPresentationDirectory(meetingId, presentationDir, presId);
|
FilenameFilter filter = new FilenameFilter() {
|
||||||
if (uploadDir != null) {
|
public boolean accept(File dir, String name) {
|
||||||
String newFilename = createNewFilename(presId, filenameExt);
|
return name.startsWith(presentationFilter);
|
||||||
String newFilePath = uploadDir.getAbsolutePath() + File.separatorChar + newFilename;
|
|
||||||
|
|
||||||
if (savePresentation(meetingId, newFilePath, address)) {
|
|
||||||
File pres = new File(newFilePath);
|
|
||||||
processUploadedFile(meetingId, presId, presFilename, pres);
|
|
||||||
} else {
|
|
||||||
log.error("Failed to download presentation=[" + address + "], meeting=[" + meetingId + "]");
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
File[] children = sourceMeetingPath.listFiles(filter);
|
||||||
|
|
||||||
|
if (children.length != 1) {
|
||||||
|
log.error("Not matching file with prefix {} found at {}",
|
||||||
|
sourceMeetingId, sourceMeetingPath);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
File sourcePresentationFile = children[0];
|
||||||
|
String filenameExt = FilenameUtils
|
||||||
|
.getExtension(sourcePresentationFile.getName());
|
||||||
|
String presId = generatePresentationId(presentationId);
|
||||||
|
String newFilename = createNewFilename(presId, filenameExt);
|
||||||
|
|
||||||
|
File uploadDir = createPresentationDirectory(destinationMeetingId,
|
||||||
|
presentationDir, presId);
|
||||||
|
String newFilePath = uploadDir.getAbsolutePath()
|
||||||
|
+ File.separatorChar + newFilename;
|
||||||
|
|
||||||
|
pageExtractor.extractPage(sourcePresentationFile, new File(
|
||||||
|
newFilePath), presentationSlide);
|
||||||
|
|
||||||
|
File pres = new File(newFilePath);
|
||||||
|
processUploadedFile(destinationMeetingId, presId, "default-"
|
||||||
|
+ presentationSlide.toString() + "." + filenameExt, pres);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,16 +76,14 @@ public class PresentationUrlDownloadService {
|
|||||||
return DigestUtils.shaHex(name) + "-" + timestamp;
|
return DigestUtils.shaHex(name) + "-" + timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFilenameExt(String filename) {
|
|
||||||
return filename.substring(filename.lastIndexOf("."));
|
|
||||||
}
|
|
||||||
|
|
||||||
public String createNewFilename(String presId, String fileExt) {
|
public String createNewFilename(String presId, String fileExt) {
|
||||||
return presId + fileExt;
|
return presId + "." + fileExt;
|
||||||
}
|
}
|
||||||
|
|
||||||
public File createPresentationDirectory(String meetingId, String presentationDir, String presentationId) {
|
public File createPresentationDirectory(String meetingId,
|
||||||
String meetingPath = presentationDir + File.separatorChar + meetingId + File.separatorChar + meetingId;
|
String presentationDir, String presentationId) {
|
||||||
|
String meetingPath = presentationDir + File.separatorChar + meetingId
|
||||||
|
+ File.separatorChar + meetingId;
|
||||||
String presPath = meetingPath + File.separatorChar + presentationId;
|
String presPath = meetingPath + File.separatorChar + presentationId;
|
||||||
File dir = new File(presPath);
|
File dir = new File(presPath);
|
||||||
log.debug("Creating dir [{}]", presPath);
|
log.debug("Creating dir [{}]", presPath);
|
||||||
@ -80,77 +93,8 @@ public class PresentationUrlDownloadService {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String followRedirect(String meetingId, String redirectUrl,
|
public void setPageExtractor(PageExtractor extractor) {
|
||||||
int redirectCount, String origUrl) {
|
this.pageExtractor = extractor;
|
||||||
|
|
||||||
if (redirectCount > maxRedirects) {
|
|
||||||
log.error("Max redirect reached for meeting=[{}] with url=[{}]", meetingId, origUrl);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
URL presUrl;
|
|
||||||
try {
|
|
||||||
presUrl = new URL(redirectUrl);
|
|
||||||
} catch (MalformedURLException e) {
|
|
||||||
log.error("Malformed url=[{}] for meeting=[{}]", redirectUrl, meetingId);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpURLConnection conn;
|
|
||||||
try {
|
|
||||||
conn = (HttpURLConnection) presUrl.openConnection();
|
|
||||||
conn.setReadTimeout(5000);
|
|
||||||
conn.addRequestProperty("Accept-Language", "en-US,en;q=0.8");
|
|
||||||
conn.addRequestProperty("User-Agent", "Mozilla");
|
|
||||||
|
|
||||||
// normally, 3xx is redirect
|
|
||||||
int status = conn.getResponseCode();
|
|
||||||
if (status != HttpURLConnection.HTTP_OK) {
|
|
||||||
if (status == HttpURLConnection.HTTP_MOVED_TEMP
|
|
||||||
|| status == HttpURLConnection.HTTP_MOVED_PERM
|
|
||||||
|| status == HttpURLConnection.HTTP_SEE_OTHER) {
|
|
||||||
String newUrl = conn.getHeaderField("Location");
|
|
||||||
return followRedirect(meetingId, newUrl, redirectCount + 1, origUrl);
|
|
||||||
} else {
|
|
||||||
log.error("Invalid HTTP response=[{}] for url=[{}] with meeting[{}]", status, redirectUrl, meetingId);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return redirectUrl;
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.error("IOException for url=[{}] with meeting[{}]", redirectUrl, meetingId);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean savePresentation(final String meetingId, final String filename,
|
|
||||||
final String urlString) {
|
|
||||||
|
|
||||||
String finalUrl = followRedirect(meetingId, urlString, 0, urlString);
|
|
||||||
|
|
||||||
if (finalUrl == null) return false;
|
|
||||||
|
|
||||||
boolean success = false;
|
|
||||||
GetMethod method = new GetMethod(finalUrl);
|
|
||||||
HttpClient client = new HttpClient();
|
|
||||||
try {
|
|
||||||
int statusCode = client.executeMethod(method);
|
|
||||||
if (statusCode == HttpStatus.SC_OK) {
|
|
||||||
FileUtils.copyInputStreamToFile(
|
|
||||||
method.getResponseBodyAsStream(), new File(filename));
|
|
||||||
log.info("Downloaded presentation at [{}]", finalUrl);
|
|
||||||
success = true;
|
|
||||||
}
|
|
||||||
} catch (HttpException e) {
|
|
||||||
log.error("HttpException while downloading presentation at [{}]", finalUrl);
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.error("IOException while downloading presentation at [{}]", finalUrl);
|
|
||||||
} finally {
|
|
||||||
method.releaseConnection();
|
|
||||||
}
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPresentationDir(String presDir) {
|
public void setPresentationDir(String presDir) {
|
||||||
@ -161,9 +105,9 @@ public class PresentationUrlDownloadService {
|
|||||||
presentationBaseURL = presentationBaseUrl;
|
presentationBaseURL = presentationBaseUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDocumentConversionService(DocumentConversionService documentConversionService) {
|
public void setDocumentConversionService(
|
||||||
|
DocumentConversionService documentConversionService) {
|
||||||
this.documentConversionService = documentConversionService;
|
this.documentConversionService = documentConversionService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,48 +1,52 @@
|
|||||||
/**
|
/**
|
||||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
* 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
|
* 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
|
* 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
|
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||||
* version.
|
* version.
|
||||||
*
|
*
|
||||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
* 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
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
* 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
|
* You should have received a copy of the GNU Lesser General Public License along
|
||||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.bigbluebutton.presentation.imp;
|
package org.bigbluebutton.presentation.imp;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
import org.bigbluebutton.presentation.PageExtractor;
|
import org.bigbluebutton.presentation.PageExtractor;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public class GhostscriptPageExtractor implements PageExtractor {
|
public class GhostscriptPageExtractor implements PageExtractor {
|
||||||
private static Logger log = LoggerFactory.getLogger(GhostscriptPageExtractor.class);
|
private static Logger log = LoggerFactory
|
||||||
|
.getLogger(GhostscriptPageExtractor.class);
|
||||||
|
|
||||||
private String GHOSTSCRIPT_EXEC;
|
private String GHOSTSCRIPT_EXEC;
|
||||||
private String noPdfMarkWorkaround;
|
private String noPdfMarkWorkaround;
|
||||||
private String SPACE = " ";
|
private String SPACE = " ";
|
||||||
|
|
||||||
public boolean extractPage(File presentationFile, File output, int page){
|
public boolean extractPage(File presentationFile, File output, int page) {
|
||||||
String OPTIONS = "-sDEVICE=pdfwrite -dNOPAUSE -dQUIET -dBATCH";
|
String OPTIONS = "-sDEVICE=pdfwrite -dNOPAUSE -dQUIET -dBATCH";
|
||||||
String FIRST_PAGE = "-dFirstPage=" + page;
|
String FIRST_PAGE = "-dFirstPage=" + page;
|
||||||
String LAST_PAGE = "-dLastPage=" + page;
|
String LAST_PAGE = "-dLastPage=" + page;
|
||||||
String DESTINATION = output.getAbsolutePath();
|
String DESTINATION = output.getAbsolutePath();
|
||||||
String OUTPUT_FILE = "-sOutputFile=" + DESTINATION;
|
String OUTPUT_FILE = "-sOutputFile=" + DESTINATION;
|
||||||
|
|
||||||
//extract that specific page and create a temp-pdf(only one page) with GhostScript
|
// extract that specific page and create a temp-pdf(only one page) with
|
||||||
String COMMAND = GHOSTSCRIPT_EXEC + SPACE + OPTIONS + SPACE + FIRST_PAGE + SPACE + LAST_PAGE + SPACE
|
// GhostScript
|
||||||
+ OUTPUT_FILE + SPACE + noPdfMarkWorkaround + SPACE + presentationFile.getAbsolutePath();
|
String COMMAND = GHOSTSCRIPT_EXEC + SPACE + OPTIONS + SPACE
|
||||||
|
+ FIRST_PAGE + SPACE + LAST_PAGE + SPACE + OUTPUT_FILE + SPACE
|
||||||
|
+ noPdfMarkWorkaround + SPACE
|
||||||
|
+ presentationFile.getAbsolutePath();
|
||||||
|
|
||||||
log.debug(COMMAND);
|
|
||||||
return new ExternalProcessExecutor().exec(COMMAND, 60000);
|
return new ExternalProcessExecutor().exec(COMMAND, 60000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user