2023-12-27 17:25:49 +00:00
window . matrix = ( opts ) => new Proxy ( {
2023-12-27 21:31:42 +00:00
el : null , // HTML element
2024-01-10 22:01:21 +01:00
profile : {
2023-12-27 17:25:49 +00:00
type : 'network' ,
2024-01-03 14:23:34 +00:00
name : '[Matrix]' ,
2023-12-27 21:31:42 +00:00
description : 'a standardized decentralized privacy-friendly protocol' ,
2023-12-27 17:25:49 +00:00
url : 'https://matrix.org' ,
2023-12-27 21:31:42 +00:00
protocol : 'matrix://' ,
2023-12-27 17:25:49 +00:00
video : false ,
audio : false ,
chat : true ,
2024-01-10 22:01:21 +01:00
scene : false
2023-12-27 17:25:49 +00:00
} ,
2024-01-10 22:01:21 +01:00
useWebcam : false ,
useChat : false ,
useScene : false ,
2024-01-09 11:05:13 +00:00
channel : '#xrfragment-test:matrix.org' ,
server : 'https://matrix.org' ,
username : '' ,
auth : 'via password' ,
authkey : '' ,
client : null ,
roomid : '' ,
2024-01-10 22:01:21 +01:00
// Matrix-CRDT
ydoc : null ,
yhref : null ,
2023-12-27 17:25:49 +00:00
html : {
2023-12-27 21:31:42 +00:00
generic : ( opts ) => ` <div>
2024-01-09 11:05:13 +00:00
< div target = "_blank" class = "badge ruler" > matrix < a onclick = "frontend.plugin.matrix.info()" > < i class = "gg-info right" > < / i > < / a > < / d i v >
< table id = "matrix" >
2023-12-27 21:31:42 +00:00
< tr >
< td > channel < / t d >
< td >
2024-01-09 11:05:13 +00:00
< input type = "text" id = "channel" placeholder = "#xrfragment:matrix.org" value = "${opts.plugin.channel}" / >
2023-12-27 21:31:42 +00:00
< / t d >
< / t r >
< tr >
< td > server < / t d >
2024-01-09 11:05:13 +00:00
< td >
< input type = "text" id = "server" placeholder = "https://matrix.org" value = "${opts.plugin.server}" / >
2023-12-27 21:31:42 +00:00
< / t d >
< / t r >
< tr >
< td > user < / t d >
< td >
< input type = "text" id = "username" placeholder = "@you:matrix.org" / >
< / t d >
< / t r >
< tr >
2023-12-28 09:22:54 +00:00
< td > auth < / t d >
2023-12-27 21:31:42 +00:00
< td >
2023-12-28 09:22:54 +00:00
< select id = "auth" >
2023-12-27 21:31:42 +00:00
< option > via password < / o p t i o n >
< option > via access token < / o p t i o n >
< / s e l e c t >
< / t d >
< / t r >
2023-12-27 17:25:49 +00:00
< tr >
2023-12-27 21:31:42 +00:00
< td > < / t d >
2023-12-27 17:25:49 +00:00
< td >
2024-01-09 11:05:13 +00:00
< input type = "password" id = "secret" placeholder = "enter password" / >
2023-12-27 17:25:49 +00:00
< / t d >
< / t r >
< / t a b l e >
2024-01-03 14:23:34 +00:00
< br >
2023-12-27 17:25:49 +00:00
< / d i v >
`
} ,
init ( ) {
2024-01-03 14:23:34 +00:00
frontend . plugin [ 'matrix' ] = this
2023-12-27 17:25:49 +00:00
$connections . chatnetwork = $connections . chatnetwork . concat ( [ this ] )
2023-12-27 21:31:42 +00:00
this . reactToConnectionHrefs ( )
2024-01-09 11:05:13 +00:00
this . nickname = localStorage . getItem ( "nickname" ) || ` human ${ String ( Math . random ( ) ) . substr ( 5 , 4 ) } `
document . addEventListener ( 'network.connect' , ( e ) => this . connect ( e . detail ) )
document . addEventListener ( 'network.init' , ( ) => {
let meeting = network . getMeetingFromUrl ( document . location . href )
2024-01-10 22:01:21 +01:00
if ( meeting . match ( this . profile . protocol ) ) {
2024-01-09 11:05:13 +00:00
this . parseLink ( meeting )
}
} )
2023-12-27 21:31:42 +00:00
} ,
connect ( opts ) {
2024-01-10 22:01:21 +01:00
if ( opts . selectedWebcam == this . profile . name ) this . useWebcam = true
if ( opts . selectedChatnetwork == this . profile . name ) this . useChat = true
if ( opts . selectedScene == this . profile . name ) this . useScene = true
if ( this . useWebcam || this . useScene || this . useChat ) {
this . link = ` matrix://r/ ${ this . channel . replace ( /^#/ , '' ) } `
console . log ( "connecting " + this . profile . name )
this . channel = document . querySelector ( "#matrix input#channel" ) . value
this . server = document . querySelector ( "#matrix input#server" ) . value
this . username = document . querySelector ( "#matrix input#username" ) . value
this . auth = document . querySelector ( "#matrix select#auth" ) . value
let secret = document . querySelector ( "#matrix input#secret" ) . value
document . querySelector ( "#matrix input#secret" ) . value = ''
let credentials = { baseUrl : this . server }
if ( this . auth == 'via access token' ) {
credentials . accessToken = secret
credentials . userId = this . username
}
this . client = Matrix . sdk . createClient ( credentials )
// Extra configuration needed for certain matrix-js-sdk
// calls to work without calling sync start functions
this . client . canSupportVoip = false ;
this . client . clientOpts = {
lazyLoadMembers : true ,
} ;
// auth
if ( this . auth == 'via password' ) {
this . client . login ( "m.login.password" , { "user" : this . username , password : secret } )
. then ( ( ) => this . onMatrixConnect ( ) )
. catch ( ( ) => window . notify ( "authentication was not succesful 😞" ) )
} else this . onMatrixConnect ( )
2024-01-09 11:05:13 +00:00
}
} ,
onMatrixConnect ( ) {
2024-01-10 22:01:21 +01:00
// token: this.matrixclient.getAccessToken()
frontend . emit ( 'network.info' , { message : '🛰 syncing with Matrix (might take a while)' , plugin : this } )
frontend . emit ( 'network.connected' , { plugin : this , username : this . username } )
this . client . startClient ( { initialSyncLimit : 4 } ) // show last 4 messages?
// get roomId of channel
this . client . getRoomIdForAlias ( this . channel )
. then ( ( o ) => {
this . roomId = o . room _id
this . setupListeners ( )
} )
. catch ( ( e ) => {
frontend . emit ( 'network.error' , { plugin : this , message : ` channel ${ this . channel } cannot be joined: ` + String ( e ) } )
} )
} ,
setupCRDT ( ) {
// Create a new Y.Doc and connect the MatrixProvider
this . ydoc = new Matrix . Y . Doc ( ) ;
const provider = new Matrix . MatrixProvider ( this . ydoc , this . client , {
type : "alias" ,
alias : this . channel
2024-01-09 11:05:13 +00:00
} ) ;
2024-01-10 22:01:21 +01:00
provider . initialize ( ) ;
this . yhref = this . ydoc . getText ( 'href' )
// observe changes of the sum
this . yhref . observe ( ( event ) => {
console . log ( "new yhref: " + yhref . toString ) ;
} ) ;
debugger
} ,
getNormalizedName ( ) {
return this . channel . replace ( /(^#|:.*)/ , '' )
2024-01-09 11:05:13 +00:00
} ,
setupListeners ( ) {
2024-01-10 22:01:21 +01:00
if ( this . useChat ) this . setupChat ( )
//if( this.useScene ) this.setupCRDT() /* throws weird errors, perhaps matrix-sdk-js is too new */
return this
} ,
setupChat ( ) {
// receive receivemessages
this . client . on ( "Room.timeline" , ( event , room , toStartOfTimeline ) => {
if ( event . getType ( ) !== "m.room.message" ) return // only print messages
if ( room . roomId == this . roomId ) {
$chat . send ( { message : event . getContent ( ) . body , from : event . getSender ( ) } )
2024-01-09 11:05:13 +00:00
}
} ) ;
2024-01-10 22:01:21 +01:00
// send chatmessages
document . addEventListener ( 'network.send' , ( e ) => {
let { message } = e . detail
let href = frontend . share ( { linkonly : true } ) // get our meetinglink in there
// convert to absolute links
if ( message . match ( /href="#/ ) ) {
message = message . replace ( /href=['"]#.*?['"]/g , ` href=" ${ href } " ` )
} else {
let pos = [ ]
if ( network . posName ) {
pos . push ( ` <a href=" ${ href } "># ${ network . posName } </a> ` )
}
if ( network . pos ) {
pos . push ( ` <a href=" ${ href } "># ${ ` pos= ${ network . pos } ` } </a> ` )
}
if ( pos . length ) message += ` <br>📍 ${ pos . join ( ' ' ) } `
}
let content = {
body : message ,
format : "org.matrix.custom.html" ,
formatted _body : message ,
msgtype : "m.text"
}
this . client . sendEvent ( this . roomId , "m.room.message" , content , "" , ( err , res ) => console . error ( err ) )
} )
2023-12-27 17:25:49 +00:00
} ,
config ( opts ) {
2024-01-10 22:01:21 +01:00
opts = { ... opts , ... this . profile }
2023-12-27 21:31:42 +00:00
this . el = document . createElement ( 'div' )
2023-12-27 17:25:49 +00:00
let html = this . html . generic ( opts )
for ( let i in opts ) {
if ( this . html [ i ] ) html += this . html [ i ] ( opts )
}
2023-12-27 21:31:42 +00:00
this . el . innerHTML = html
2023-12-28 09:22:54 +00:00
this . el . querySelector ( '#auth' ) . addEventListener ( 'change' , ( e ) => {
this . el . querySelector ( '#secret' ) . setAttribute ( 'placeholder' , ` enter ${ e . target . value . replace ( /.* / , '' ) } ` )
} )
2023-12-27 21:31:42 +00:00
return this . el
} ,
2024-01-09 11:05:13 +00:00
info ( opts ) {
2024-01-10 22:01:21 +01:00
window . notify ( ` ${ this . profile . name } is ${ this . profile . description } , it is the hottest internet technology available at this moment.<br>Read more about it <a href=" ${ this . profile . url } " target="_blank">here</a>.<br>You can basically make up a new channelname or use an existing one ` )
2024-01-09 11:05:13 +00:00
} ,
parseLink ( url ) {
2024-01-10 22:01:21 +01:00
if ( ! url . match ( this . profile . protocol ) ) return
let parts = url . replace ( this . profile . protocol , '' ) . split ( "/" )
2024-01-09 11:05:13 +00:00
if ( parts [ 0 ] == 'r' ) { // room
let server = parts . split ( "/" ) [ 1 ] . replace ( /:.*/ , '' )
let channel = parts . split ( "/" ) [ 1 ] . replace ( /.*:/ , '' )
$connections . show ( )
2024-01-10 22:01:21 +01:00
$connections . selectedChatnetwork = this . profile . name
$connections . selectedScene = this . profile . name
2024-01-09 11:05:13 +00:00
this . el . querySelector ( '#channel' ) . value = ` # ${ channel } : ${ server } `
this . el . querySelector ( '#server' ) . value = server
console . log ( "configured matrix" )
}
return false
} ,
2024-01-10 22:01:21 +01:00
t0nkr0nst0nreateLink ( opts ) {
let hash = document . location . hash
if ( ! this . link ) {
const meeting = network . getMeetingFromUrl ( document . location . href )
this . link = meeting . match ( "matrix://" ) ? meeting : ''
}
if ( ! hash . match ( 'meet=' ) ) document . location . hash += ` ${ hash . length > 1 ? '&' : '#' } meet= ${ this . link } `
} ,
2023-12-27 21:31:42 +00:00
reactToConnectionHrefs ( ) {
xrf . addEventListener ( 'href' , ( opts ) => {
let { mesh } = opts
if ( ! opts . click ) return
2024-01-09 11:05:13 +00:00
this . parseLink ( mesh . userData . href )
let href = mesh . userData . href
let isLocal = href [ 0 ] == '#'
let isTeleport = href . match ( /(pos=|http:)/ )
2024-01-10 22:01:21 +01:00
console . log ( "href detected" )
if ( isLocal && ! isTeleport && this . client && this . useScene ) {
console . log ( "sending href" )
this . yhref . set ( document . location . hash )
}
2023-12-27 17:25:49 +00:00
} )
2024-01-09 11:05:13 +00:00
let hashvars = xrf . URI . parse ( document . location . hash )
if ( hashvars . meet ) this . parseLink ( hashvars . meet . string )
2023-12-27 17:25:49 +00:00
}
} ,
{
// auto-trigger events on changes
get ( data , k , receiver ) { return data [ k ] } ,
set ( data , k , v ) {
let from = data [ k ]
data [ k ] = v
2023-12-27 21:31:42 +00:00
//switch( k ){
// default: matrix.opts.scene.dispatchEvent({type:`matrix.${k}.change`, from, to:v})
//}
2023-12-27 17:25:49 +00:00
}
} )
document . addEventListener ( '$connections:ready' , ( e ) => {
matrix ( e . detail ) . init ( )
} )