-
-
Notifications
You must be signed in to change notification settings - Fork 247
add webrtc support #1284
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
Draft
dank074
wants to merge
28
commits into
spacebarchat:master
Choose a base branch
from
dank074:dev/webrtc-shit
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
add webrtc support #1284
Changes from all commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
e2b9924
start adding some abstraction
dank074 96e4573
more stuff
dank074 77b8d45
a lot of changes
dank074 b13198c
extract stuff to external library
dank074 623f8fc
update package-lock
dank074 5bae44f
changes
dank074 1ff3828
change
dank074 625cf56
changes
dank074 dd079f9
we dont need this
dank074 54f6685
add schemas for stream gateway messages
dank074 c845d20
updates
dank074 9e20280
changes
dank074 4e5c40b
disable udp voice connections
dank074 1b526e2
can now watch golive streams
dank074 3ce16f5
update types
dank074 2d4f3b0
send voice states on connect
dank074 bbcd690
update event types + schema
dank074 bf8a88d
hide private voice state tokens from whole guild
dank074 36461b3
remove unused voice stuff
dank074 f04526d
clear voice state on disconnect
dank074 c3bf004
add migration
dank074 8d1fa40
update types
dank074 7b5dac4
run prettier
dank074 11bb278
don't need this
dank074 4592ff1
fix weird timing issue with onVideo message
dank074 f28ebd1
set timeout when waiting for connection
dank074 fa19cd0
webrtc gateway shouldnt remove session on close
dank074 b826061
also clear guild_id from voicestate on disconnect
dank074 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
import { | ||
genVoiceToken, | ||
Payload, | ||
WebSocket, | ||
generateStreamKey, | ||
} from "@spacebar/gateway"; | ||
import { | ||
Channel, | ||
Config, | ||
emitEvent, | ||
Member, | ||
Region, | ||
Snowflake, | ||
Stream, | ||
StreamCreateEvent, | ||
StreamCreateSchema, | ||
StreamServerUpdateEvent, | ||
StreamSession, | ||
VoiceState, | ||
VoiceStateUpdateEvent, | ||
} from "@spacebar/util"; | ||
import { check } from "./instanceOf"; | ||
|
||
export async function onStreamCreate(this: WebSocket, data: Payload) { | ||
check.call(this, StreamCreateSchema, data.d); | ||
const body = data.d as StreamCreateSchema; | ||
|
||
if (body.channel_id.trim().length === 0) return; | ||
|
||
// first check if we are in a voice channel already. cannot create a stream if there's no existing voice connection | ||
const voiceState = await VoiceState.findOne({ | ||
where: { user_id: this.user_id }, | ||
}); | ||
|
||
if (!voiceState || !voiceState.channel_id) return; | ||
|
||
if (body.guild_id) { | ||
voiceState.member = await Member.findOneOrFail({ | ||
where: { id: voiceState.user_id, guild_id: voiceState.guild_id }, | ||
relations: ["user", "roles"], | ||
}); | ||
} | ||
|
||
// TODO: permissions check - if it's a guild, check if user is allowed to create stream in this guild | ||
|
||
const channel = await Channel.findOne({ | ||
where: { id: body.channel_id }, | ||
}); | ||
|
||
if ( | ||
!channel || | ||
(body.type === "guild" && channel.guild_id != body.guild_id) | ||
) | ||
return this.close(4000, "invalid channel"); | ||
|
||
// TODO: actually apply preferred_region from the event payload | ||
const regions = Config.get().regions; | ||
const guildRegion = regions.available.filter( | ||
(r) => r.id === regions.default, | ||
)[0]; | ||
|
||
// first make sure theres no other streams for this user that somehow didnt get cleared | ||
await Stream.delete({ | ||
owner_id: this.user_id, | ||
}); | ||
|
||
// create a new entry in db containing the token for authenticating user in stream gateway IDENTIFY | ||
const stream = Stream.create({ | ||
id: Snowflake.generate(), | ||
owner_id: this.user_id, | ||
channel_id: body.channel_id, | ||
endpoint: guildRegion.endpoint, | ||
}); | ||
|
||
await stream.save(); | ||
|
||
const token = genVoiceToken(); | ||
|
||
const streamSession = StreamSession.create({ | ||
stream_id: stream.id, | ||
user_id: this.user_id, | ||
session_id: this.session_id, | ||
token, | ||
}); | ||
|
||
await streamSession.save(); | ||
|
||
const streamKey = generateStreamKey( | ||
body.type, | ||
body.guild_id, | ||
body.channel_id, | ||
this.user_id, | ||
); | ||
|
||
await emitEvent({ | ||
event: "STREAM_CREATE", | ||
data: { | ||
stream_key: streamKey, | ||
rtc_server_id: stream.id, // for voice connections in guilds it is guild_id, for dm voice calls it seems to be DM channel id, for GoLive streams a generated number | ||
viewer_ids: [], | ||
region: guildRegion.name, | ||
paused: false, | ||
}, | ||
user_id: this.user_id, | ||
} as StreamCreateEvent); | ||
|
||
await emitEvent({ | ||
event: "STREAM_SERVER_UPDATE", | ||
data: { | ||
token: streamSession.token, | ||
stream_key: streamKey, | ||
guild_id: null, // not sure why its always null | ||
endpoint: stream.endpoint, | ||
}, | ||
user_id: this.user_id, | ||
} as StreamServerUpdateEvent); | ||
|
||
voiceState.self_stream = true; | ||
await voiceState.save(); | ||
|
||
await emitEvent({ | ||
event: "VOICE_STATE_UPDATE", | ||
data: voiceState.toPublicVoiceState(), | ||
guild_id: voiceState.guild_id, | ||
channel_id: voiceState.channel_id, | ||
} as VoiceStateUpdateEvent); | ||
} | ||
|
||
//stream key: | ||
// guild:${guild_id}:${channel_id}:${user_id} | ||
// call:${channel_id}:${user_id} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import { parseStreamKey, Payload, WebSocket } from "@spacebar/gateway"; | ||
import { | ||
emitEvent, | ||
Stream, | ||
StreamDeleteEvent, | ||
StreamDeleteSchema, | ||
VoiceState, | ||
VoiceStateUpdateEvent, | ||
} from "@spacebar/util"; | ||
import { check } from "./instanceOf"; | ||
|
||
export async function onStreamDelete(this: WebSocket, data: Payload) { | ||
check.call(this, StreamDeleteSchema, data.d); | ||
const body = data.d as StreamDeleteSchema; | ||
|
||
let parsedKey: { | ||
type: "guild" | "call"; | ||
channelId: string; | ||
guildId?: string; | ||
userId: string; | ||
}; | ||
|
||
try { | ||
parsedKey = parseStreamKey(body.stream_key); | ||
} catch (e) { | ||
return this.close(4000, "Invalid stream key"); | ||
} | ||
|
||
const { userId, channelId, guildId, type } = parsedKey; | ||
|
||
// when a user selects to stop watching another user stream, this event gets triggered | ||
// just disconnect user without actually deleting stream | ||
if (this.user_id !== userId) { | ||
await emitEvent({ | ||
event: "STREAM_DELETE", | ||
data: { | ||
stream_key: body.stream_key, | ||
}, | ||
user_id: this.user_id, | ||
} as StreamDeleteEvent); | ||
return; | ||
} | ||
|
||
const stream = await Stream.findOne({ | ||
where: { channel_id: channelId, owner_id: userId }, | ||
}); | ||
|
||
if (!stream) return; | ||
|
||
await stream.remove(); | ||
|
||
const voiceState = await VoiceState.findOne({ | ||
where: { user_id: this.user_id }, | ||
}); | ||
|
||
if (voiceState) { | ||
voiceState.self_stream = false; | ||
await voiceState.save(); | ||
|
||
await emitEvent({ | ||
event: "VOICE_STATE_UPDATE", | ||
data: voiceState.toPublicVoiceState(), | ||
guild_id: guildId, | ||
channel_id: channelId, | ||
} as VoiceStateUpdateEvent); | ||
} | ||
|
||
await emitEvent({ | ||
event: "STREAM_DELETE", | ||
data: { | ||
stream_key: body.stream_key, | ||
}, | ||
guild_id: guildId, | ||
channel_id: channelId, | ||
} as StreamDeleteEvent); | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
once this is merged, it'd be best for the org to take over this repo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Additionally, can we somehow get this on npm? some deployment methods dont support using github uris in nodejs packages
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree that it should be an org repo. Once merged repo will be transferred and it can be published under a spacebar npm account