Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

xAPI preparation and more #29

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.git/
node_modules/
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
node_modules/
log/*
config/default.yml
*.orig
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
8.4.0
18
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ ENV NODE_ENV production

WORKDIR /app

ADD package.json package-lock.json /app/
COPY package.json package-lock.json /app/

RUN npm install \
&& npm cache clear --force

ADD . /app
COPY . /app

RUN cp config/default.example.yml config/default.yml

Expand Down
6 changes: 6 additions & 0 deletions config/custom-environment-variables.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ bbb:
serverDomain: SERVER_DOMAIN
sharedSecret: SHARED_SECRET
auth2_0: BEARER_AUTH
includeEvents:
__name: INCLUDE_EVENTS
__format: json
excludeEvents:
__name: EXCLUDE_EVENTS
__format: json
hooks:
permanentURLs:
__name: PERMANENT_HOOKS
Expand Down
6 changes: 5 additions & 1 deletion config/default.example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ bbb:
# Whether to use Auth2.0 or not, Auth2.0 sends the sharedSecret whithin an Authorization header as a bearer
auth2_0: false
apiPath: /bigbluebutton/api
# Empty to include all events; if non-empty, only these events will be fired
includeEvents: []
# Empty to include all events; if non-empty, only these events won't be fired
excludeEvents: []

# The port in which the API server will run.
server:
Expand Down Expand Up @@ -54,7 +58,7 @@ hooks:
# Mappings of internal to external meeting IDs
mappings:
cleanupInterval: 10000 # 10 secs, in ms
timeout: 86400000 # 24 hours, in ms
timeout: 604800000 # 1 week, in ms

# Redis
redis:
Expand Down
65 changes: 60 additions & 5 deletions messageMapping.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ module.exports = class MessageMapping {
this.padEvents = [
"PadContentEvtMsg"
];
this.pollEvents = [
"PollStartedEvtMsg",
"UserRespondedToPollRespMsg",
];
}

// Map internal message based on it's type
Expand All @@ -89,6 +93,8 @@ module.exports = class MessageMapping {
this.compRapTemplate(messageObj);
} else if (this.mappedEvent(messageObj,this.padEvents)) {
this.padTemplate(messageObj);
} else if (this.mappedEvent(messageObj,this.pollEvents)) {
this.pollTemplate(messageObj);
}
}

Expand Down Expand Up @@ -128,6 +134,7 @@ module.exports = class MessageMapping {
"external-meeting-id": props.meetingProp.extId,
"name": props.meetingProp.name,
"is-breakout": props.meetingProp.isBreakout,
"parent-id": props.breakoutProps.parentId,
"duration": props.durationProps.duration,
"create-time": props.durationProps.createdTime,
"create-date": props.durationProps.createdDate,
Expand Down Expand Up @@ -213,6 +220,7 @@ module.exports = class MessageMapping {
"name": msgBody.name,
"role": msgBody.role,
"presenter": msgBody.presenter,
"userdata": msgBody.userdata,
"stream": msgBody.stream
}
},
Expand All @@ -226,6 +234,10 @@ module.exports = class MessageMapping {
} else if (this.mappedObject.data["id"] === "user-audio-voice-disabled") {
this.mappedObject.data["attributes"]["user"]["listening-only"] = false;
this.mappedObject.data["attributes"]["user"]["sharing-mic"] = false;
} else if (this.mappedObject.data["id"] === "user-emoji-changed") {
if (msgBody.emoji !== "none") {
this.mappedObject.data["attributes"]["user"]["emoji"] = msgBody.emoji;
}
}
this.mappedMessage = JSON.stringify(this.mappedObject);
Logger.info(`[MessageMapping] Mapped message: ${this.mappedMessage}`);
Expand Down Expand Up @@ -308,11 +320,11 @@ module.exports = class MessageMapping {
"external-meeting-id": IDMapping.getExternalMeetingID(messageObj.envelope.routing.meetingId)
},
"chat-message":{
"id": body.msg.id,
"message": body.msg.message,
"sender":{
"internal-user-id": body.msg.sender.id,
"external-user-id": body.msg.sender.name,
"timezone-offset": body.msg.fromTimezoneOffset,
"name": body.msg.sender.name,
"time": body.msg.timestamp
}
},
Expand Down Expand Up @@ -372,6 +384,11 @@ module.exports = class MessageMapping {
this.mappedObject.data.attributes["step-time"] = data.step_time;
}

if (this.mappedObject.data.id === "rap-archive-ended") {
this.mappedObject.data.attributes["recorded"] = data.recorded || false;
this.mappedObject.data.attributes["duration"] = data.duration || 0;
}

if (data.workflow) {
this.mappedObject.data.attributes.workflow = data.workflow;
}
Expand All @@ -380,10 +397,10 @@ module.exports = class MessageMapping {
this.mappedObject.data.attributes.recording = {
"name": data.metadata.meetingName,
"is-breakout": data.metadata.isBreakout,
"start-time": data.startTime,
"end-time": data.endTime,
"start-time": data.start_time,
"end-time": data.end_time,
"size": data.playback.size,
"raw-size": data.rawSize,
"raw-size": data.raw_size,
"metadata": data.metadata,
"playback": data.playback,
"download": data.download
Expand Down Expand Up @@ -450,6 +467,42 @@ module.exports = class MessageMapping {
Logger.info(`[MessageMapping] Mapped message: ${this.mappedMessage}`);
}

pollTemplate(messageObj) {
const msgBody = messageObj.core.body;
const msgHeader = messageObj.core.header;
const extId = UserMapping.getExternalUserID(msgHeader.userId) || msgBody.extId || "";
this.mappedObject.data = {
"type": "event",
"id": this.mapInternalMessage(messageObj),
"attributes":{
"meeting":{
"internal-meeting-id": messageObj.envelope.routing.meetingId,
"external-meeting-id": IDMapping.getExternalMeetingID(messageObj.envelope.routing.meetingId)
},
"user":{
"internal-user-id": msgHeader.userId,
"external-user-id": extId,
},
"poll":{
"id": msgBody.pollId
}
},
"event":{
"ts": Date.now()
}
};

if (this.mappedObject.data["id"] === "poll-started") {
this.mappedObject.data["attributes"]["poll"]["question"] = msgBody.question;
this.mappedObject.data["attributes"]["poll"]["answers"] = msgBody.poll.answers;
} else if (this.mappedObject.data["id"] === "poll-responded") {
this.mappedObject.data["attributes"]["poll"]["answerIds"] = msgBody.answerIds;
}

this.mappedMessage = JSON.stringify(this.mappedObject);
Logger.info(`[MessageMapping] Mapped message: ${this.mappedMessage}`);
}

mapInternalMessage(message) {
let name;
if (message.envelope) {
Expand Down Expand Up @@ -506,6 +559,8 @@ module.exports = class MessageMapping {
case "video_stream_unpublished": return "user-cam-broadcast-end";
case "user_status_changed_message": return this.handleUserStatusChanged(message);
case "PadContentEvtMsg": return "pad-content";
case "PollStartedEvtMsg": return "poll-started";
case "UserRespondedToPollRespMsg": return "poll-responded";
} })();
return mappedMsg;
}
Expand Down
Loading