286 lines
9.5 KiB
JavaScript
286 lines
9.5 KiB
JavaScript
window.matrix = (opts) => new Proxy({
|
|
|
|
el: null, // HTML element
|
|
|
|
profile:{
|
|
type: 'network',
|
|
name: '[Matrix]',
|
|
description: 'a standardized decentralized privacy-friendly protocol',
|
|
url: 'https://matrix.org',
|
|
protocol: 'matrix://',
|
|
video: false,
|
|
audio: false,
|
|
chat: true,
|
|
scene: false
|
|
},
|
|
|
|
useWebcam: false,
|
|
useChat: false,
|
|
useScene: false,
|
|
|
|
channel: '#xrfragment-test:matrix.org',
|
|
server: 'https://matrix.org',
|
|
username:'',
|
|
auth: 'via password',
|
|
authkey: '',
|
|
client: null,
|
|
roomid: '',
|
|
|
|
// Matrix-CRDT
|
|
ydoc: null,
|
|
yhref: null,
|
|
|
|
html: {
|
|
generic: (opts) => `<div>
|
|
<div target="_blank" class="badge ruler">matrix <a onclick="frontend.plugin.matrix.info()"><i class="gg-info right"></i></a></div>
|
|
<table id="matrix">
|
|
<tr>
|
|
<td>channel</td>
|
|
<td>
|
|
<input type="text" id="channel" placeholder="#xrfragment:matrix.org" value="${opts.plugin.channel}"/>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>server</td>
|
|
<td>
|
|
<input type="text" id="server" placeholder="https://matrix.org" value="${opts.plugin.server}"/>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>user</td>
|
|
<td>
|
|
<input type="text" id="username" placeholder="@you:matrix.org"/>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>auth</td>
|
|
<td>
|
|
<select id="auth">
|
|
<option>via password</option>
|
|
<option>via access token</option>
|
|
</select>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td></td>
|
|
<td>
|
|
<input type="password" id="secret" placeholder="enter password"/>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<br>
|
|
</div>
|
|
`
|
|
},
|
|
|
|
init(){
|
|
frontend.plugin['matrix'] = this
|
|
$connections.chatnetwork = $connections.chatnetwork.concat([this])
|
|
this.reactToConnectionHrefs()
|
|
|
|
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)
|
|
if( meeting.match(this.profile.protocol) ){
|
|
this.parseLink( meeting )
|
|
}
|
|
})
|
|
},
|
|
|
|
connect(opts){
|
|
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()
|
|
}
|
|
},
|
|
|
|
onMatrixConnect(){
|
|
// 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
|
|
});
|
|
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(/(^#|:.*)/,'')
|
|
},
|
|
|
|
setupListeners(){
|
|
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()})
|
|
}
|
|
});
|
|
|
|
// 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) )
|
|
})
|
|
|
|
},
|
|
|
|
config(opts){
|
|
opts = {...opts, ...this.profile }
|
|
this.el = document.createElement('div')
|
|
let html = this.html.generic(opts)
|
|
for( let i in opts ){
|
|
if( this.html[i] ) html += this.html[i](opts)
|
|
}
|
|
this.el.innerHTML = html
|
|
this.el.querySelector('#auth').addEventListener('change', (e) => {
|
|
this.el.querySelector('#secret').setAttribute('placeholder', `enter ${e.target.value.replace(/.* /,'')}`)
|
|
})
|
|
return this.el
|
|
},
|
|
|
|
info(opts){
|
|
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`)
|
|
},
|
|
|
|
parseLink(url){
|
|
if( !url.match(this.profile.protocol) ) return
|
|
let parts = url.replace(this.profile.protocol,'').split("/")
|
|
if( parts[0] == 'r' ){ // room
|
|
let server = parts.split("/")[1].replace(/:.*/,'')
|
|
let channel = parts.split("/")[1].replace(/.*:/,'')
|
|
$connections.show()
|
|
$connections.selectedChatnetwork = this.profile.name
|
|
$connections.selectedScene = this.profile.name
|
|
this.el.querySelector('#channel').value = `#${channel}:${server}`
|
|
this.el.querySelector('#server').value = server
|
|
console.log("configured matrix")
|
|
}
|
|
return false
|
|
},
|
|
|
|
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}`
|
|
},
|
|
|
|
reactToConnectionHrefs(){
|
|
xrf.addEventListener('href', (opts) => {
|
|
let {mesh} = opts
|
|
if( !opts.click ) return
|
|
this.parseLink(mesh.userData.href)
|
|
let href = mesh.userData.href
|
|
let isLocal = href[0] == '#'
|
|
let isTeleport = href.match(/(pos=|http:)/)
|
|
console.log("href detected")
|
|
if( isLocal && !isTeleport && this.client && this.useScene ){
|
|
console.log("sending href")
|
|
this.yhref.set( document.location.hash )
|
|
}
|
|
})
|
|
let hashvars = xrf.URI.parse( document.location.hash )
|
|
if( hashvars.meet ) this.parseLink(hashvars.meet.string)
|
|
}
|
|
},
|
|
{
|
|
// auto-trigger events on changes
|
|
get(data,k,receiver){ return data[k] },
|
|
set(data,k,v){
|
|
let from = data[k]
|
|
data[k] = v
|
|
//switch( k ){
|
|
// default: matrix.opts.scene.dispatchEvent({type:`matrix.${k}.change`, from, to:v})
|
|
//}
|
|
}
|
|
})
|
|
|
|
document.addEventListener('$connections:ready', (e) => {
|
|
matrix(e.detail).init()
|
|
})
|
|
|