Skip to content
This repository has been archived by the owner on Aug 21, 2024. It is now read-only.

Commit

Permalink
pushing dev to int (#10896)
Browse files Browse the repository at this point in the history
* Revert "Physics reactivity for collider component updates and order dependenc…" (#10876)

This reverts commit 33afb3b.

* fix collider reactivity (#10877)

* fix collider reactivity

* fix tests

* optimize

* fix duplicate new scene (#10880)

* rigidbody initialization quick fix (#10883)

* Upload drag drop files MT fix (#10881)

* Upload drag drop files MT fix

* Array length check

* LerpTransform from rigid body uses rigid body instead of scene entity (#10882)

* remove old workflows (#10886)

* fix rigidbody crash server (#10891)

* IR-3561: Magic Link template support for mobile and desktop  (#10889)

* feat: refactor magic link email template to support desktop and mobile
chore: layout template to reuse styles in other templates

* Fixed logo link

---------

Co-authored-by: Hanzla Mateen <[email protected]>

* Fixed bugs in instanceserver connections (#10887)

* Fixed bugs in instanceserver connections

There were still some bugs surrounding a client connecting to an
instanceserver if the instance record for that server no longer
existed. updateInstance needed to return false in that situation.

This still led to a situation where the client would be stuck trying
to authenticate forever. Added a step prior to authentication where
the client listens for a message with { instanceReady: true }, which
is sent by setupSocketFunctions. If the server isn't ready within
10 seconds, then it returns { instanceReady: false }, and the client
will do a new instanceserver provision and hopefully connect properly
this time.

* make eslint happy

---------

Co-authored-by: Josh Field <[email protected]>

---------

Co-authored-by: Josh Field <[email protected]>
Co-authored-by: Michael Estes <[email protected]>
Co-authored-by: Daniel Belmes <[email protected]>
Co-authored-by: lucas3900 <[email protected]>
Co-authored-by: Kyle Baran <[email protected]>
Co-authored-by: José Galván <[email protected]>
Co-authored-by: Hanzla Mateen <[email protected]>
  • Loading branch information
8 people authored Aug 6, 2024
1 parent bde4b45 commit 4e57a1c
Show file tree
Hide file tree
Showing 7 changed files with 205 additions and 49 deletions.
2 changes: 1 addition & 1 deletion .env.local.default
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ KEY=certs/key.pem

# Client variables ---------------
APP_TITLE="IR Engine"
APP_LOGO=https://etherealengine-static.s3-us-east-1.amazonaws.com/logo.png
APP_LOGO=https://preview.ir.world/static/ir.svg
APP_URL=https://localhost:3000
APP_HOST=localhost:3000
APP_PORT=3000
Expand Down
113 changes: 86 additions & 27 deletions packages/client-core/src/transports/SocketWebRTCClientFunctions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ import { getSearchParamFromURL } from '@etherealengine/common/src/utils/getSearc
import { Engine } from '@etherealengine/ecs/src/Engine'
import { defineSystem, destroySystem } from '@etherealengine/ecs/src/SystemFunctions'
import { PresentationSystemGroup } from '@etherealengine/ecs/src/SystemGroups'
import { AuthTask } from '@etherealengine/engine/src/avatar/functions/receiveJoinWorld'
import { AuthTask, ReadyTask } from '@etherealengine/engine/src/avatar/functions/receiveJoinWorld'
import { Identifiable, PeerID, State, dispatchAction, getMutableState, getState, none } from '@etherealengine/hyperflux'
import {
Action,
Expand Down Expand Up @@ -98,6 +98,8 @@ import {
stopFaceTracking,
stopLipsyncTracking
} from '../media/webcam/WebcamInput'
import { ChannelState } from '../social/services/ChannelService'
import { LocationState } from '../social/services/LocationService'
import { AuthState } from '../user/services/AuthService'
import { MediaStreamState, MediaStreamService as _MediaStreamService } from './MediaStreams'
import { clearPeerMediaChannels } from './PeerMediaChannelState'
Expand Down Expand Up @@ -221,7 +223,7 @@ export const connectToInstance = (
if (instanceStillProvisioned(instanceID, locationID, channelID)) _connect()
}, 3000)

const onConnect = () => {
const onConnect = async () => {
if (aborted || !primus) return
connecting = false
primus.off('incoming::open', onConnect)
Expand All @@ -230,31 +232,49 @@ export const connectToInstance = (
clearTimeout(connectionFailTimeout)

const topic = locationID ? NetworkTopics.world : NetworkTopics.media
authenticatePrimus(primus, instanceID, topic)

/** Server closed the connection. */
const onDisconnect = () => {
if (aborted) return
if (primus) {
primus.off('incoming::end', onDisconnect)
primus.off('end', onDisconnect)
const instanceserverReady = await checkInstanceserverReady(primus, instanceID, topic)
if (instanceserverReady) {
await authenticatePrimus(primus, instanceID, topic)

/** Server closed the connection. */
const onDisconnect = () => {
if (aborted) return
if (primus) {
primus.off('incoming::end', onDisconnect)
primus.off('end', onDisconnect)
}
const network = getState(NetworkState).networks[instanceID] as SocketWebRTCClientNetwork
if (!network) return logger.error('Disconnected from unconnected instance ' + instanceID)

logger.info('Disconnected from network %o', { topic: network.topic, id: network.id })
/**
* If we are disconnected (server closes our socket) rather than leave the network,
* we just need to destroy and recreate the transport
*/
closeNetwork(network)
/** If we still have the instance provisioned, we should try again */
if (instanceStillProvisioned(instanceID, locationID, channelID)) _connect()
}
// incoming::end is emitted when the server closes the connection
primus.on('incoming::end', onDisconnect)
// end is emitted when the client closes the connection
primus.on('end', onDisconnect)
} else {
if (locationID) {
const currentLocation = getMutableState(LocationState).currentLocation.location
const currentLocationId = currentLocation.id.value
currentLocation.id.set(undefined as unknown as LocationID)
currentLocation.id.set(currentLocationId)
} else {
const channelState = getMutableState(ChannelState)
const targetChannelId = channelState.targetChannelId.value
channelState.targetChannelId.set(undefined as unknown as ChannelID)
channelState.targetChannelId.set(targetChannelId)
}
const network = getState(NetworkState).networks[instanceID] as SocketWebRTCClientNetwork
if (!network) return logger.error('Disconnected from unconnected instance ' + instanceID)

logger.info('Disonnected from network %o', { topic: network.topic, id: network.id })
/**
* If we are disconnected (server closes our socket) rather than leave the network,
* we just need to destroy and recreate the transport
*/
closeNetwork(network)
/** If we still have the instance provisioned, we should try again */
if (instanceStillProvisioned(instanceID, locationID, channelID)) _connect()
primus.removeAllListeners()
primus.end()
console.log('PRIMUS GONE')
}
// incoming::end is emitted when the server closes the connection
primus.on('incoming::end', onDisconnect)
// end is emitted when the client closes the connection
primus.on('end', onDisconnect)
}
primus!.on('incoming::open', onConnect)
}
Expand Down Expand Up @@ -283,6 +303,45 @@ export const getChannelIdFromTransport = (network: SocketWebRTCClientNetwork) =>
return isWorldConnection ? null : currentChannelInstanceConnection?.channelId
}

export async function checkInstanceserverReady(primus: Primus, instanceID: InstanceID, topic: Topic) {
logger.info('Checking that instanceserver is ready')
const { instanceReady } = await new Promise<ReadyTask>((resolve) => {
const onStatus = (response: ReadyTask) => {
// eslint-disable-next-line no-prototype-builtins
if (response.hasOwnProperty('instanceReady')) {
clearInterval(interval)
resolve(response)
primus.off('data', onStatus)
primus.removeListener('incoming::end', onDisconnect)
}
}

primus.on('data', onStatus)

let disconnected = false
const interval = setInterval(() => {
if (disconnected) {
clearInterval(interval)
resolve({ instanceReady: false })
primus.removeAllListeners()
primus.end()
return
}
}, 100)

const onDisconnect = () => {
disconnected = true
}
primus.addListener('incoming::end', onDisconnect)
})

if (!instanceReady) {
unprovisionInstance(topic, instanceID)
}

return instanceReady
}

export async function authenticatePrimus(primus: Primus, instanceID: InstanceID, topic: Topic) {
logger.info('Authenticating instance ' + instanceID)

Expand Down Expand Up @@ -325,10 +384,10 @@ export async function authenticatePrimus(primus: Primus, instanceID: InstanceID,
/** We failed to connect to be authenticated, we do not want to try again */
// TODO: do we want to unprovision here?
unprovisionInstance(topic, instanceID)
return logger.error(new Error('Unable to connect with credentials' + error))
return logger.error(new Error('Unable to connect with credentials ' + error))
}

connectToNetwork(primus, instanceID, topic, hostPeerID!, routerRtpCapabilities!, cachedActions!)
await connectToNetwork(primus, instanceID, topic, hostPeerID!, routerRtpCapabilities!, cachedActions!)
}

export const connectToNetwork = async (
Expand Down
4 changes: 4 additions & 0 deletions packages/engine/src/avatar/functions/receiveJoinWorld.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ export type AuthTask = {
error?: AuthError
}

export type ReadyTask = {
instanceReady: boolean
}

export type JoinWorldRequestData = {
inviteCode?: InviteCode
}
Expand Down
18 changes: 16 additions & 2 deletions packages/instanceserver/src/SocketFunctions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ import { getServerNetwork } from './SocketWebRTCServerFunctions'

const logger = multiLogger.child({ component: 'instanceserver:spark' })

const NON_READY_INTERVALS = 100 //100 tenths of a second, i.e. 10 seconds

export const setupSocketFunctions = async (app: Application, spark: any) => {
let authTask: AuthTask | undefined

Expand All @@ -50,15 +52,27 @@ export const setupSocketFunctions = async (app: Application, spark: any) => {
*
* Authorize user and make sure everything is valid before allowing them to join the world
**/
await new Promise<void>((resolve) => {
const ready = await new Promise<boolean>((resolve) => {
let counter = 0
const interval = setInterval(() => {
counter++
if (getState(InstanceServerState).ready) {
clearInterval(interval)
resolve()
resolve(true)
}
if (counter > NON_READY_INTERVALS) {
clearInterval(interval)
resolve(false)
}
}, 100)
})

if (!ready) {
app.primus.write({ instanceReady: false })
return
}

app.primus.write({ instanceReady: true })
const network = getServerNetwork(app)

const onAuthenticationRequest = async (data) => {
Expand Down
10 changes: 7 additions & 3 deletions packages/instanceserver/src/channels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -409,9 +409,13 @@ const updateInstance = async ({
if (isNeedingNewServer && !instanceStarted) {
instanceStarted = true
const initialized = await initializeInstance({ app, status, headers, userId })
if (initialized) await loadEngine({ app, sceneId, headers })
else instanceStarted = false
return true
if (initialized) {
await loadEngine({ app, sceneId, headers })
return true
} else {
instanceStarted = false
return false
}
} else {
try {
if (!getState(InstanceServerState).ready)
Expand Down
80 changes: 80 additions & 0 deletions packages/server-core/email-templates/account/layout.pug
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
//- layout.pug
doctype html
html
head
style.
body{
font-family: Roboto, Arial;
height: 100%;
width: auto;
background: #fff;
margin: 0;
padding-top: 2.5rem;
}
.container {
width: 75%;
max-width: 75%;
height: auto;
margin: 0 auto;
background: #383650;
box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px;
padding: 2rem;
padding-bottom: 4rem;
border-radius: 10px;
}
.main {
margin: 0 auto;
max-width: 90%;
}
.header {
padding-bottom: 2rem;
}
.logo{
display: block;
margin: 0 auto;
heigh: auto;
max-width: 3em;
max-height: 4em;
}
.title-container{
background: #5045AB;
padding: 2rem;
}
.message-container{
background: #fff;
padding: 2rem;
}
h1 {
color: #fff;
font-size: 1.8rem;
text-wrap: wrap;
text-overflow: ellipsis;
}
h2 {
color: #918EAD;
}
p {
color: #8f9299;
font-weight: bold;
}
a {
word-wrap: break-word;
}
.link-btn {
width: 96%;
display: inline-block;
background: #5045AB;
text-align: center;
padding: 0.6rem;
border-radius: 5px;
text-decoration: none;
color: #fff !important;
font-weight: bold;
font-size: 1.2rem;
}
body
div(class='container')
.header
img(src=logo, class='logo')
.main
block content
27 changes: 11 additions & 16 deletions packages/server-core/email-templates/account/magiclink-email.pug
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
doctype html
body(style='margin: 0;')
div(style='margin: 0 auto; width:75%;background: #fff;')
div(style='margin-top:40px;height: auto;background: #383650;box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px;padding: 4rem; border-radius: 10px;')
.hd(style='padding-bottom:30px')
img(src=logo, style='display: block; margin: 0 auto; max-width: 6em;')
.main
div(style='background: #5045AB;padding: 3rem 4rem 1.5rem 4rem;')
h1(style='font-family: Roboto, Arial; color: #fff;font-size: 1.8rem;') You've Got The Magic Link!
div(style='background: #fff;padding: 2rem;')
h2(style='font-family: Roboto, Arial;color: #918EAD;') Hi 👋!
p(style='font-family: Roboto, Arial;color: #8f9299;font-weight: bold;') You asked us to send you a magic link for quickly signing into your account.
a(href=hashLink, style='font-family: Roboto, Arial;width: 96%;display: inline-block;background: #5045AB;text-align: center;padding: 0.6rem;border-radius: 5px;text-decoration: none;color: #fff;font-weight: bold;font-size: 1.2rem;font-family: Roboto, Arial;') Sign In Now!
div
p(style='color: #8f9299;font-weight: bold;font-family: Roboto, Arial;') Or copy and paste this link into your browser:
a(style='word-wrap: break-word;', href=hashLink) #{hashLink}
extends layout.pug
block content
.title-container
h1 You've Got The Magic Link!
.message-container
h2 Hi 👋!
p You asked us to send you a magic link for quickly signing into your account.
a(href=hashLink class='link-btn') Sign In Now!
div
p Or copy and paste this link into your browser:
a(href=hashLink) #{hashLink}

0 comments on commit 4e57a1c

Please sign in to comment.