Merge pull request #17972 from gustavotrott/graphql-media-sharing
refactor (graphql-server): Add externalVideo and screenshare to Graphql
This commit is contained in:
commit
1d870a294c
@ -4,7 +4,8 @@ import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.apps.{ ExternalVideoModel, PermissionCheck, RightsManagementTrait }
|
||||
import org.bigbluebutton.core.bus.MessageBus
|
||||
import org.bigbluebutton.core.running.LiveMeeting
|
||||
import org.bigbluebutton.core.apps.screenshare.ScreenshareApp2x.{ requestBroadcastStop }
|
||||
import org.bigbluebutton.core.apps.screenshare.ScreenshareApp2x.requestBroadcastStop
|
||||
import org.bigbluebutton.core.db.ExternalVideoDAO
|
||||
|
||||
trait StartExternalVideoPubMsgHdlr extends RightsManagementTrait {
|
||||
this: ExternalVideoApp2x =>
|
||||
@ -39,6 +40,7 @@ trait StartExternalVideoPubMsgHdlr extends RightsManagementTrait {
|
||||
requestBroadcastStop(bus.outGW, liveMeeting)
|
||||
|
||||
ExternalVideoModel.setURL(liveMeeting.externalVideoModel, msg.body.externalVideoUrl)
|
||||
ExternalVideoDAO.insert(liveMeeting.props.meetingProp.intId, msg.body.externalVideoUrl)
|
||||
broadcastEvent(msg)
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package org.bigbluebutton.core.apps.externalvideo
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.apps.{ ExternalVideoModel, PermissionCheck, RightsManagementTrait }
|
||||
import org.bigbluebutton.core.bus.MessageBus
|
||||
import org.bigbluebutton.core.db.ExternalVideoDAO
|
||||
import org.bigbluebutton.core.running.LiveMeeting
|
||||
import org.bigbluebutton.core2.message.senders.MsgBuilder
|
||||
|
||||
@ -19,6 +20,8 @@ trait StopExternalVideoPubMsgHdlr extends RightsManagementTrait {
|
||||
} else {
|
||||
ExternalVideoModel.clear(liveMeeting.externalVideoModel)
|
||||
|
||||
ExternalVideoDAO.updateStopped(liveMeeting.props.meetingProp.intId)
|
||||
|
||||
//broadcastEvent
|
||||
val msgEvent = MsgBuilder.buildStopExternalVideoEvtMsg(liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
bus.outGW.send(msgEvent)
|
||||
|
@ -3,7 +3,8 @@ package org.bigbluebutton.core.apps.externalvideo
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
||||
import org.bigbluebutton.core.bus.MessageBus
|
||||
import org.bigbluebutton.core.running.{ LiveMeeting }
|
||||
import org.bigbluebutton.core.db.ExternalVideoDAO
|
||||
import org.bigbluebutton.core.running.LiveMeeting
|
||||
|
||||
trait UpdateExternalVideoPubMsgHdlr extends RightsManagementTrait {
|
||||
|
||||
@ -24,6 +25,7 @@ trait UpdateExternalVideoPubMsgHdlr extends RightsManagementTrait {
|
||||
val reason = "You need to be the presenter to update external video"
|
||||
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
|
||||
} else {
|
||||
ExternalVideoDAO.update(liveMeeting.props.meetingProp.intId, msg.body.status, msg.body.rate, msg.body.time, msg.body.state)
|
||||
broadcastEvent(msg)
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
package org.bigbluebutton.core.apps.screenshare
|
||||
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.apps.{ ScreenshareModel, ExternalVideoModel }
|
||||
import org.bigbluebutton.core.apps.{ ExternalVideoModel, ScreenshareModel }
|
||||
import org.bigbluebutton.core.bus.MessageBus
|
||||
import org.bigbluebutton.core.db.ScreenshareDAO
|
||||
import org.bigbluebutton.core.running.LiveMeeting
|
||||
|
||||
trait ScreenshareRtmpBroadcastStartedVoiceConfEvtMsgHdlr {
|
||||
@ -48,6 +49,8 @@ trait ScreenshareRtmpBroadcastStartedVoiceConfEvtMsgHdlr {
|
||||
|
||||
log.info("START broadcast ALLOWED when isBroadcastingRTMP=false")
|
||||
|
||||
ScreenshareDAO.insert(liveMeeting.props.meetingProp.intId, liveMeeting.screenshareModel)
|
||||
|
||||
// Notify viewers in the meeting that there's an rtmp stream to view
|
||||
val msgEvent = broadcastEvent(msg.body.voiceConf, msg.body.screenshareConf, msg.body.stream,
|
||||
msg.body.vidWidth, msg.body.vidHeight, msg.body.timestamp, msg.body.hasAudio)
|
||||
|
@ -2,10 +2,12 @@ package org.bigbluebutton.core.apps.screenshare
|
||||
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.apps.ScreenshareModel
|
||||
import org.bigbluebutton.core.apps.ScreenshareModel.getRTMPBroadcastingUrl
|
||||
import org.bigbluebutton.core.bus.MessageBus
|
||||
import org.bigbluebutton.core.running.LiveMeeting
|
||||
import org.bigbluebutton.core2.message.senders.MsgBuilder
|
||||
import org.bigbluebutton.core.apps.screenshare.ScreenshareApp2x.{ broadcastStopped }
|
||||
import org.bigbluebutton.core.apps.screenshare.ScreenshareApp2x.broadcastStopped
|
||||
import org.bigbluebutton.core.db.ScreenshareDAO
|
||||
|
||||
trait ScreenshareRtmpBroadcastStoppedVoiceConfEvtMsgHdlr {
|
||||
this: ScreenshareApp2x =>
|
||||
@ -15,6 +17,8 @@ trait ScreenshareRtmpBroadcastStoppedVoiceConfEvtMsgHdlr {
|
||||
ScreenshareModel.isBroadcastingRTMP(liveMeeting.screenshareModel) + " URL:" +
|
||||
ScreenshareModel.getRTMPBroadcastingUrl(liveMeeting.screenshareModel))
|
||||
|
||||
ScreenshareDAO.updateStopped(liveMeeting.props.meetingProp.intId, getRTMPBroadcastingUrl(liveMeeting.screenshareModel))
|
||||
|
||||
broadcastStopped(bus.outGW, liveMeeting)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,86 @@
|
||||
package org.bigbluebutton.core.db
|
||||
|
||||
import org.bigbluebutton.core.util.RandomStringGenerator
|
||||
import slick.jdbc.PostgresProfile.api._
|
||||
import slick.lifted.ProvenShape
|
||||
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.util.{Failure, Success}
|
||||
|
||||
case class ExternalVideoDbModel(
|
||||
externalVideoId: String,
|
||||
meetingId: String,
|
||||
externalVideoUrl: String,
|
||||
startedAt: java.sql.Timestamp = new java.sql.Timestamp(System.currentTimeMillis()),
|
||||
stoppedAt: Option[java.sql.Timestamp],
|
||||
lastEventAt: Option[java.sql.Timestamp],
|
||||
lastEventDesc: String,
|
||||
playerRate: Double,
|
||||
playerTime: Double,
|
||||
playerState: Int
|
||||
)
|
||||
|
||||
class ExternalVideoDbTableDef(tag: Tag) extends Table[ExternalVideoDbModel](tag, "external_video") {
|
||||
val externalVideoId = column[String]("externalVideoId", O.PrimaryKey)
|
||||
val meetingId = column[String]("meetingId")
|
||||
val externalVideoUrl = column[String]("externalVideoUrl")
|
||||
val startedAt = column[java.sql.Timestamp]("startedAt")
|
||||
val stoppedAt = column[Option[java.sql.Timestamp]]("stoppedAt")
|
||||
val lastEventAt = column[Option[java.sql.Timestamp]]("lastEventAt")
|
||||
val lastEventDesc = column[String]("lastEventDesc")
|
||||
val playerRate = column[Double]("playerRate")
|
||||
val playerTime = column[Double]("playerTime")
|
||||
val playerState = column[Int]("playerState")
|
||||
override def * : ProvenShape[ExternalVideoDbModel] = (externalVideoId, meetingId, externalVideoUrl, startedAt, stoppedAt, lastEventAt, lastEventDesc, playerRate, playerTime, playerState) <> (ExternalVideoDbModel.tupled, ExternalVideoDbModel.unapply)
|
||||
}
|
||||
|
||||
object ExternalVideoDAO {
|
||||
def insert(meetingId: String, externalVideoUrl: String) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[ExternalVideoDbTableDef].forceInsert(
|
||||
ExternalVideoDbModel(
|
||||
externalVideoId = System.currentTimeMillis() + "-" + RandomStringGenerator.randomAlphanumericString(8),
|
||||
meetingId = meetingId,
|
||||
externalVideoUrl = externalVideoUrl,
|
||||
startedAt = new java.sql.Timestamp(System.currentTimeMillis()),
|
||||
stoppedAt = None,
|
||||
lastEventAt = None,
|
||||
lastEventDesc = "",
|
||||
playerRate = 0,
|
||||
playerTime = 0,
|
||||
playerState = 0,
|
||||
)
|
||||
)
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"$rowsAffected row(s) inserted in ExternalVideo table!")
|
||||
case Failure(e) => DatabaseConnection.logger.error(s"Error inserting ExternalVideo: $e")
|
||||
}
|
||||
}
|
||||
|
||||
def update(meetingId: String, status: String, rate: Double, time: Double, state: Int) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[ExternalVideoDbTableDef]
|
||||
.filter(_.meetingId === meetingId)
|
||||
.filter(_.stoppedAt.isEmpty)
|
||||
.map(ev => (ev.lastEventDesc, ev.playerRate, ev.playerTime, ev.playerState, ev.lastEventAt))
|
||||
.update((status, rate, time, state, Some(new java.sql.Timestamp(System.currentTimeMillis()))))
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"$rowsAffected row(s) updated on ExternalVideo table!")
|
||||
case Failure(e) => DatabaseConnection.logger.debug(s"Error updating ExternalVideo: $e")
|
||||
}
|
||||
}
|
||||
|
||||
def updateStopped(meetingId: String) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[ExternalVideoDbTableDef]
|
||||
.filter(_.meetingId === meetingId)
|
||||
.filter(_.stoppedAt.isEmpty)
|
||||
.map(ev => ev.stoppedAt)
|
||||
.update(Some(new java.sql.Timestamp(System.currentTimeMillis())))
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"$rowsAffected row(s) updated stoppedAt on ExternalVideo table!")
|
||||
case Failure(e) => DatabaseConnection.logger.debug(s"Error updating stoppedAt on ExternalVideo: $e")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
package org.bigbluebutton.core.db
|
||||
|
||||
import org.bigbluebutton.core.apps.ScreenshareModel
|
||||
import org.bigbluebutton.core.apps.ScreenshareModel.{ getHasAudio, getRTMPBroadcastingUrl, getScreenshareConf, getScreenshareVideoHeight, getScreenshareVideoWidth, getVoiceConf }
|
||||
import org.bigbluebutton.core.util.RandomStringGenerator
|
||||
import slick.jdbc.PostgresProfile.api._
|
||||
import slick.lifted.ProvenShape
|
||||
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.util.{ Failure, Success }
|
||||
|
||||
case class ScreenshareDbModel(
|
||||
screenshareId: String,
|
||||
meetingId: String,
|
||||
voiceConf: String,
|
||||
screenshareConf: String,
|
||||
stream: String,
|
||||
vidWidth: Int,
|
||||
vidHeight: Int,
|
||||
startedAt: java.sql.Timestamp = new java.sql.Timestamp(System.currentTimeMillis()),
|
||||
stoppedAt: Option[java.sql.Timestamp],
|
||||
hasAudio: Boolean
|
||||
)
|
||||
|
||||
class ScreenshareDbTableDef(tag: Tag) extends Table[ScreenshareDbModel](tag, "screenshare") {
|
||||
val screenshareId = column[String]("screenshareId", O.PrimaryKey)
|
||||
val meetingId = column[String]("meetingId")
|
||||
val voiceConf = column[String]("voiceConf")
|
||||
val screenshareConf = column[String]("screenshareConf")
|
||||
val stream = column[String]("stream")
|
||||
val vidWidth = column[Int]("vidWidth")
|
||||
val vidHeight = column[Int]("vidHeight")
|
||||
val startedAt = column[java.sql.Timestamp]("startedAt")
|
||||
val stoppedAt = column[Option[java.sql.Timestamp]]("stoppedAt")
|
||||
val hasAudio = column[Boolean]("hasAudio")
|
||||
override def * : ProvenShape[ScreenshareDbModel] = (screenshareId, meetingId, voiceConf, screenshareConf, stream, vidWidth, vidHeight, startedAt, stoppedAt, hasAudio) <> (ScreenshareDbModel.tupled, ScreenshareDbModel.unapply)
|
||||
}
|
||||
|
||||
object ScreenshareDAO {
|
||||
def insert(meetingId: String, screenshareModel: ScreenshareModel) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[ScreenshareDbTableDef].forceInsert(
|
||||
ScreenshareDbModel(
|
||||
screenshareId = System.currentTimeMillis() + "-" + RandomStringGenerator.randomAlphanumericString(8),
|
||||
meetingId = meetingId,
|
||||
voiceConf = getVoiceConf(screenshareModel),
|
||||
screenshareConf = getScreenshareConf(screenshareModel),
|
||||
stream = getRTMPBroadcastingUrl(screenshareModel),
|
||||
vidWidth = getScreenshareVideoWidth(screenshareModel),
|
||||
vidHeight = getScreenshareVideoHeight(screenshareModel),
|
||||
startedAt = new java.sql.Timestamp(System.currentTimeMillis()),
|
||||
stoppedAt = None,
|
||||
hasAudio = getHasAudio(screenshareModel)
|
||||
)
|
||||
)
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"$rowsAffected row(s) inserted in Screenshare table!")
|
||||
case Failure(e) => DatabaseConnection.logger.error(s"Error inserting Screenshare: $e")
|
||||
}
|
||||
}
|
||||
|
||||
def updateStopped(meetingId: String, stream: String) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[ScreenshareDbTableDef]
|
||||
.filter(_.meetingId === meetingId)
|
||||
.filter(_.stream === stream)
|
||||
.filter(_.stoppedAt.isEmpty)
|
||||
.map(ev => ev.stoppedAt)
|
||||
.update(Some(new java.sql.Timestamp(System.currentTimeMillis())))
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"$rowsAffected row(s) updated stoppedAt on Screenshare table!")
|
||||
case Failure(e) => DatabaseConnection.logger.debug(s"Error updating stoppedAt on Screenshare: $e")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -61,6 +61,10 @@ drop view if exists "v_poll";
|
||||
drop table if exists "poll_response";
|
||||
drop table if exists "poll_option";
|
||||
drop table if exists "poll";
|
||||
drop view if exists "v_external_video";
|
||||
drop table if exists "external_video";
|
||||
drop view if exists "v_screenshare";
|
||||
drop table if exists "screenshare";
|
||||
|
||||
|
||||
DROP FUNCTION IF EXISTS "update_user_presenter_trigger_func";
|
||||
@ -851,7 +855,7 @@ CREATE INDEX "idx_poll_response_pollId" ON "poll_response"("pollId");
|
||||
CREATE INDEX "idx_poll_response_userId" ON "poll_response"("userId");
|
||||
CREATE INDEX "idx_poll_response_pollId_userId" ON "poll_response"("pollId", "userId");
|
||||
|
||||
CREATE OR REPLACE VIEW v_poll_response AS
|
||||
CREATE OR REPLACE VIEW "v_poll_response" AS
|
||||
SELECT
|
||||
poll."meetingId",
|
||||
poll."pollId",
|
||||
@ -869,7 +873,7 @@ LEFT JOIN poll_response r ON r."pollId" = poll."pollId" AND o."optionId" = r."op
|
||||
GROUP BY poll."pollId", o."optionId", o."optionDesc"
|
||||
ORDER BY poll."pollId";
|
||||
|
||||
CREATE VIEW v_poll_user AS
|
||||
CREATE VIEW "v_poll_user" AS
|
||||
SELECT
|
||||
poll."meetingId",
|
||||
poll."pollId",
|
||||
@ -886,10 +890,54 @@ LEFT JOIN poll_response r ON r."pollId" = poll."pollId" AND r."userId" = u."user
|
||||
LEFT JOIN poll_option o ON o."pollId" = r."pollId" AND o."optionId" = r."optionId"
|
||||
GROUP BY poll."pollId", u."userId", u.name ;
|
||||
|
||||
CREATE VIEW v_poll AS SELECT * FROM poll;
|
||||
CREATE VIEW "v_poll" AS SELECT * FROM "poll";
|
||||
|
||||
CREATE VIEW v_poll_option AS
|
||||
SELECT poll."meetingId", poll."pollId", o."optionId", o."optionDesc"
|
||||
FROM poll_option o
|
||||
JOIN poll using("pollId")
|
||||
WHERE poll."type" != 'R-';
|
||||
|
||||
--------------------------------
|
||||
----External video
|
||||
|
||||
create table "external_video"(
|
||||
"externalVideoId" varchar(100) primary key,
|
||||
"meetingId" varchar(100) REFERENCES "meeting"("meetingId") ON DELETE CASCADE,
|
||||
"externalVideoUrl" varchar(500),
|
||||
"startedAt" timestamp,
|
||||
"stoppedAt" timestamp,
|
||||
"lastEventAt" timestamp,
|
||||
"lastEventDesc" varchar(50),
|
||||
"playerRate" numeric,
|
||||
"playerTime" numeric,
|
||||
"playerState" integer
|
||||
);
|
||||
create index "external_video_meetingId_current" on "external_video"("meetingId") WHERE "stoppedAt" IS NULL;
|
||||
|
||||
CREATE VIEW "v_external_video" AS
|
||||
SELECT * FROM "external_video"
|
||||
WHERE "stoppedAt" IS NULL;
|
||||
|
||||
--------------------------------
|
||||
----Screenshare
|
||||
|
||||
|
||||
create table "screenshare"(
|
||||
"screenshareId" varchar(50) primary key,
|
||||
"meetingId" varchar(100) REFERENCES "meeting"("meetingId") ON DELETE CASCADE,
|
||||
"voiceConf" varchar(50),
|
||||
"screenshareConf" varchar(50),
|
||||
"stream" varchar(100),
|
||||
"vidWidth" integer,
|
||||
"vidHeight" integer,
|
||||
"startedAt" timestamp,
|
||||
"stoppedAt" timestamp,
|
||||
"hasAudio" boolean
|
||||
);
|
||||
create index "screenshare_meetingId" on "screenshare"("meetingId");
|
||||
create index "screenshare_meetingId_current" on "screenshare"("meetingId") WHERE "stoppedAt" IS NULL;
|
||||
|
||||
CREATE VIEW "v_screenshare" AS
|
||||
SELECT * FROM "screenshare"
|
||||
WHERE "stoppedAt" IS NULL;
|
||||
|
@ -11,6 +11,15 @@ object_relationships:
|
||||
remote_table:
|
||||
name: v_meeting_breakoutPolicies
|
||||
schema: public
|
||||
- name: externalVideo
|
||||
using:
|
||||
manual_configuration:
|
||||
column_mapping:
|
||||
meetingId: meetingId
|
||||
insertion_order: null
|
||||
remote_table:
|
||||
name: v_external_video
|
||||
schema: public
|
||||
- name: lockSettings
|
||||
using:
|
||||
manual_configuration:
|
||||
@ -29,6 +38,15 @@ object_relationships:
|
||||
remote_table:
|
||||
name: v_meeting_recordingPolicies
|
||||
schema: public
|
||||
- name: screenshare
|
||||
using:
|
||||
manual_configuration:
|
||||
column_mapping:
|
||||
meetingId: meetingId
|
||||
insertion_order: null
|
||||
remote_table:
|
||||
name: v_screenshare
|
||||
schema: public
|
||||
- name: usersPolicies
|
||||
using:
|
||||
manual_configuration:
|
||||
|
@ -0,0 +1,24 @@
|
||||
table:
|
||||
name: v_external_video
|
||||
schema: public
|
||||
configuration:
|
||||
column_config: {}
|
||||
custom_column_names: {}
|
||||
custom_name: external_video
|
||||
custom_root_fields: {}
|
||||
select_permissions:
|
||||
- role: bbb_client
|
||||
permission:
|
||||
columns:
|
||||
- externalVideoId
|
||||
- externalVideoUrl
|
||||
- lastEventAt
|
||||
- lastEventDesc
|
||||
- playerRate
|
||||
- playerState
|
||||
- playerTime
|
||||
- startedAt
|
||||
- stoppedAt
|
||||
filter:
|
||||
meetingId:
|
||||
_eq: X-Hasura-MeetingId
|
@ -0,0 +1,24 @@
|
||||
table:
|
||||
name: v_screenshare
|
||||
schema: public
|
||||
configuration:
|
||||
column_config: {}
|
||||
custom_column_names: {}
|
||||
custom_name: screenshare
|
||||
custom_root_fields: {}
|
||||
select_permissions:
|
||||
- role: bbb_client
|
||||
permission:
|
||||
columns:
|
||||
- hasAudio
|
||||
- screenshareConf
|
||||
- screenshareId
|
||||
- startedAt
|
||||
- stoppedAt
|
||||
- stream
|
||||
- vidHeight
|
||||
- vidWidth
|
||||
- voiceConf
|
||||
filter:
|
||||
meetingId:
|
||||
_eq: X-Hasura-MeetingId
|
@ -4,6 +4,7 @@
|
||||
- "!include public_v_chat.yaml"
|
||||
- "!include public_v_chat_message_private.yaml"
|
||||
- "!include public_v_chat_message_public.yaml"
|
||||
- "!include public_v_external_video.yaml"
|
||||
- "!include public_v_meeting_breakoutPolicies.yaml"
|
||||
- "!include public_v_meeting_group.yaml"
|
||||
- "!include public_v_meeting_lockSettings.yaml"
|
||||
@ -19,6 +20,7 @@
|
||||
- "!include public_v_pres_annotation_history_curr.yaml"
|
||||
- "!include public_v_pres_page_cursor.yaml"
|
||||
- "!include public_v_pres_page_writers.yaml"
|
||||
- "!include public_v_screenshare.yaml"
|
||||
- "!include public_v_user.yaml"
|
||||
- "!include public_v_user_breakoutRoom.yaml"
|
||||
- "!include public_v_user_camera.yaml"
|
||||
|
Loading…
Reference in New Issue
Block a user