From 720ccb2d2e15939bd8f15a9d2aa156418c464791 Mon Sep 17 00:00:00 2001 From: f0x Date: Fri, 22 Mar 2019 16:40:30 +0100 Subject: [PATCH] matrix-js-sdk and login screen --- app.js | 77 +++++++++++++++++---- backends/matrix.js | 145 +++++++++++++++------------------------ components/chat.js | 20 +++++- components/filterList.js | 6 +- components/sidebar.js | 7 +- package.json | 2 + public/scss/style.scss | 47 +++++++++++++ shrinkwrap.yaml | 126 +++++++++++++++++++++++++++++++--- 8 files changed, 313 insertions(+), 117 deletions(-) diff --git a/app.js b/app.js index 531ba01..53b6162 100644 --- a/app.js +++ b/app.js @@ -3,6 +3,7 @@ const React = require('react') const ReactDOM = require('react-dom') const create = require('create-react-class') const Promise = require('bluebird') +const urllib = require('url') const Matrix = require('./backends/matrix.js') @@ -18,37 +19,87 @@ const Input = require('./components/input.js') // incoming/outgoing message alignment (split) -let backend = new Matrix("user", "pass", "https://lain.haus") -backend.sync() let App = create({ displayName: "App", getInitialState: function() { - return this.checkBackend() + return {rooms: {}, events: {}} }, checkBackend: function() { - let returnValue = null - if(backend.hasUpdates()) { - returnValue = { - rooms: backend.getRooms(), - events: backend.getEvents() - } + if(this.state.backend.hasUpdates()) { + console.log("RECEIVING UPDATES FROM BACKEND") + this.setState({ + rooms: this.state.backend.getRooms(), + events: this.state.backend.getEvents() + }) } setTimeout(() => { - this.setState(this.checkBackend()) + this.checkBackend() }, 100) - return returnValue + }, + + login: function() { + let user = document.getElementById("user").value + let pass = document.getElementById("pass").value + let hs = document.getElementById("hs").value + hs = urllib.parse(hs) + + let data = { + user: user, + password: pass, + type: "m.login.password", + initial_device_display_name: "Neo v4", + }; + + let url = urllib.format(Object.assign(hs, { + pathname: "/_matrix/client/r0/login" + })); + + fetch(url, { + body: JSON.stringify(data), + headers: { + 'content-type': 'application/json' + }, + method: 'POST', + }).then((response) => response.json()) + .then((responseJson) => { + this.setState({json: responseJson}); + if(responseJson.access_token != undefined) { + let backend = new Matrix(responseJson.user_id, responseJson.access_token, "https://"+responseJson.home_server) + this.setState({ + backend: backend + }) + this.checkBackend() + } + }) + .catch((error) => { + console.error(error); + }); }, render: function() { + if (this.state.backend == undefined) { + //Login screen + return ( +
+ +
+ + + + +
+
+ ) + } return ( <> - + {this.setState({roomId: roomId})}}/>
- +
diff --git a/backends/matrix.js b/backends/matrix.js index 9fd1d3c..7253abb 100644 --- a/backends/matrix.js +++ b/backends/matrix.js @@ -2,83 +2,53 @@ const React = require('react') const ReactDOM = require('react-dom') const defaultValue = require('default-value') +const sdk = require('matrix-js-sdk') class Matrix { - constructor(user, password, homeserver) { + constructor(user, token, homeserver) { this.user = user; - this.password = password; this.homeserver = homeserver; - this.a = 0 - this.events = { - "roomId": [ - { - type: "m.room.message", - sender: "@f0x:lain.haus", - content: { - body: "Image caption", - info: { - size: 1331429, - mimetype: "image/png", - thumbnail_info: { - w: 600, - h: 600, - mimetype: "image/png", - size: 151911 - }, - w: 2000, - h: 2000, - thumbnail_url: "mxc://lain.haus/PnptnVmLprDNICfhCqIIurHZ" - }, - msgtype: "m.image", - url: "mxc://lain.haus/MXtCRwxheuSEVsIyHfyUGJNz" - }, - event_id: "$155317808164309EPnWP:lain.haus", - origin_server_ts: 1553178081145, - unsigned: { - age: 587, - transaction_id: "m1553178080798.12" - }, - room_id: "!bghqZrxFTiDyEUzunK:disroot.org" - } - ] - } + this.client = sdk.createClient({ + baseUrl: homeserver, + accessToken: token, + userId: user + }); - //this.rooms = ["Neo", "version 4", "Codename", "Iris", "Let's All Love Lain", "Very long room name abcdefghijklmnopqrstuvwxyz"] - this.rooms = { - "room0": { - name: "Neo", - lastEvent: 10 - }, - "room1": { - name: "v4: iris", - lastEvent: 10 - }, - "room2": { - name: "groups", - lastEvent: 10 - }, - "room3": { - name: "GUI Demo", - lastEvent: 0 - } - } + this.events = {} + this.rooms = {} + this.startClient() this.updates = true } + startClient() { + this.client.on("Room.timeline", (event, room, toStartOfTimeline) => { + if (toStartOfTimeline) { + return + } + if (this.events[room.roomId] == undefined) { + this.events[room.roomId] = [] + this.rooms[room.roomId] = { + name: room.name, + lastEvent: 0 + } + } + this.events[room.roomId].push(event.event) + this.updates = true + console.log("NEW EVENTS") + }) + this.client.startClient() + } + getHS() { return this.homeserver } getEvents(roomId) { - return this.events["roomId"] + return this.events } getRooms() { - let orderList = Object.keys(this.rooms) - orderList.sort((a, b) => { - return this.rooms[b].lastEvent - this.rooms[a].lastEvent - }) - return {rooms: this.rooms, order: orderList} + return this.rooms } hasUpdates() { @@ -89,36 +59,33 @@ class Matrix { return false } - addEvent(event) { - this.events["roomId"].push(event) - } - sync() { - let rand = this.lastRand - while(rand == this.lastRand) { - rand = Math.floor(Math.random()*Object.keys(this.rooms).length) - } - this.lastRand = rand - let roomId = `room${rand}` - let now = new Date().getMilliseconds() - this.rooms[roomId].lastEvent = now - this.updates = true + // let rand = this.lastRand + // while(rand == this.lastRand) { + // rand = Math.floor(Math.random()*Object.keys(this.rooms).length) + // } + // this.lastRand = rand + // let roomId = `room${rand}` + // let now = new Date().getMilliseconds() + // this.rooms[roomId].lastEvent = now + // this.updates = true + + // let event = { + // content: { + // body: "New m.text Event", + // msgtype: "m.text" + // }, + // event_id: this.fakeEventId(), + // origin_server_ts: 1432735824653, + // room_id: "!jEsUZKDJdhlrceRyVU:domain.com", + // sender: "@example:domain.com", + // type: "m.room.message", + // unsigned: { + // age: 1234 + // } + // } + // this.events["roomId"].push(event) - let event = { - content: { - body: "Testing m.text", - msgtype: "m.text" - }, - event_id: this.fakeEventId(), - origin_server_ts: 1432735824653, - room_id: "!jEsUZKDJdhlrceRyVU:domain.com", - sender: "@example:domain.com", - type: "m.room.message", - unsigned: { - age: 1234 - } - } - this.events["roomId"].push(event) setTimeout(() => {this.sync()}, 2000) } diff --git a/components/chat.js b/components/chat.js index 92ccdfa..7d7e100 100644 --- a/components/chat.js +++ b/components/chat.js @@ -27,8 +27,15 @@ jdenticon.config = { let chat = create({ displayName: "Chat", + getInitialState: function() { + return { + ref: null + } + }, + getSnapshotBeforeUpdate: function(oldProps, oldState) { let ref = this.state.ref + if (ref == null) {return} if ((ref.scrollHeight - ref.offsetHeight) - ref.scrollTop < 100) { // Less than 100px from bottom return true } @@ -37,6 +44,7 @@ let chat = create({ componentDidUpdate(prevProps, prevState, snapshot) { let ref = this.state.ref + if (ref == null) {return} if (snapshot) { // scroll to bottom ref.scrollTop = (ref.scrollHeight - ref.offsetHeight) } @@ -49,6 +57,14 @@ let chat = create({ }, render: function() { + if (this.props.roomId == undefined || this.props.events[this.props.roomId] == undefined) { + //empty screen + return
+
+
+
+ } + let messageGroups = { current: [], groups: [], @@ -58,7 +74,7 @@ let chat = create({ // if the sender is the same, add it to the 'current' messageGroup, if not, // push the old one to 'groups' and start with a new array. - this.props.events.forEach((event, id) => { + this.props.events[this.props.roomId].forEach((event, id) => { if (event.sender != messageGroups.sender) { messageGroups.sender = event.sender if (messageGroups.current.length != 0) { @@ -115,7 +131,7 @@ let EventGroup = create({ function getRenderedEvent(event, id, backend) { if (event.type == "m.room.message") { let msgtype = event.content.msgtype; - return React.createElement(elements[defaultValue(msgtype, "m.text")], {event: event, key: id, backend: backend}) + return React.createElement(defaultValue(elements[msgtype], elements["m.text"]), {event: event, key: id, backend: backend}) } } diff --git a/components/filterList.js b/components/filterList.js index 0584c28..0e8f680 100644 --- a/components/filterList.js +++ b/components/filterList.js @@ -17,7 +17,7 @@ let FilterList = create({ select: function(id) { this.setState({selection: id}) - //this.props.callback(id) + this.props.callback(id) }, inputRef: function(ref) { @@ -37,9 +37,9 @@ let FilterList = create({ }, render: function() { - let items = Object.keys(this.props.items).map((itemKey, id) => { + let keys = Object.keys(this.props.items) + let items = keys.map((itemKey, id) => { let item = this.props.items[itemKey] - let props = { selected: this.state.selection == itemKey, filter: this.state.filter, diff --git a/components/sidebar.js b/components/sidebar.js index 36f81fa..acef70f 100644 --- a/components/sidebar.js +++ b/components/sidebar.js @@ -4,6 +4,7 @@ const ReactDOM = require('react-dom') const create = require('create-react-class') const Promise = require('bluebird') const debounce = require('debounce') +const jdenticon = require('jdenticon') const FilterList = require('./filterList.js') @@ -17,6 +18,10 @@ let RoomListItem = create({ } }, + componentDidMount() { + jdenticon.update("svg") + }, + setRef: function(ref) { if (ref == null) { return @@ -61,7 +66,7 @@ let Sidebar = create({ render: function() { return
- + {this.props.selectRoom(roomId)}}/>
} }) diff --git a/package.json b/package.json index d805745..b3929ce 100644 --- a/package.json +++ b/package.json @@ -35,9 +35,11 @@ "gulp-util": "^3.0.8", "jdenticon": "^2.1.1", "livereactload": "^4.0.0-beta.2", + "matrix-js-sdk": "^1.0.2", "react": "^16.6.3", "react-dom": "^16.6.3", "sanitize-html": "^1.20.0", + "sourceify": "^0.1.0", "vinyl-buffer": "^1.0.1", "vinyl-source-stream": "^2.0.0", "webpack": "^4.27.1" diff --git a/public/scss/style.scss b/public/scss/style.scss index cd050e8..a5a5304 100644 --- a/public/scss/style.scss +++ b/public/scss/style.scss @@ -48,6 +48,53 @@ body { height: 100vh; width: 100vw; display: flex; + justify-content: center; +} + +.loginwrapper { + margin-top: -15rem; + display: flex; + justify-content: center; + flex-direction: column; + + img { + height: 15rem; + width: 15rem; + text-align: center; + align-self: center; + } +} + +.login { + align-self: center; + display: inline-grid; + grid-template-columns: 1fr 1fr; + + $blue: #5294e2; + + label, input, button { + margin: 0.3rem; + padding: 0.3rem; + } + + label { + background: $blue; + justify-self: left; + } + + input { + border: 0.1rem solid $blue; + background: transparent; + color: white; + } + + button { + grid-column-start: 2; + background: $blue; + color: white; + justify-self: right; + border: none; + } } .main { diff --git a/shrinkwrap.yaml b/shrinkwrap.yaml index 3ed9d2a..cc5aeca 100644 --- a/shrinkwrap.yaml +++ b/shrinkwrap.yaml @@ -25,9 +25,11 @@ dependencies: gulp-util: 3.0.8 jdenticon: 2.1.1 livereactload: 4.0.0-beta.2 + matrix-js-sdk: 1.0.2 react: 16.6.3 react-dom: 16.6.3 sanitize-html: 1.20.0 + sourceify: 0.1.0 vinyl-buffer: 1.0.1 vinyl-source-stream: 2.0.0 webpack: 4.27.1 @@ -989,6 +991,15 @@ packages: ajv: ^6.0.0 resolution: integrity: sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo= + /ajv/6.10.0: + dependencies: + fast-deep-equal: 2.0.1 + fast-json-stable-stringify: 2.0.0 + json-schema-traverse: 0.4.1 + uri-js: 4.2.2 + dev: false + resolution: + integrity: sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg== /ajv/6.6.2: dependencies: fast-deep-equal: 2.0.1 @@ -1004,6 +1015,10 @@ packages: node: '>=0.4.2' resolution: integrity: sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU= + /another-json/0.2.0: + dev: false + resolution: + integrity: sha1-tfQBnJc7bdXGUGotk0acttMq7tw= /ansi-colors/1.1.0: dependencies: ansi-wrap: 0.1.0 @@ -1393,6 +1408,13 @@ packages: dev: false resolution: integrity: sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== + /babel-runtime/6.26.0: + dependencies: + core-js: 2.6.5 + regenerator-runtime: 0.11.1 + dev: false + resolution: + integrity: sha1-llxwWGaOgrVde/4E/yM3vItWR/4= /babelify/10.0.0: dev: false engines: @@ -1421,6 +1443,18 @@ packages: dev: false resolution: integrity: sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + /base-x/3.0.4: + dependencies: + safe-buffer: 5.1.2 + dev: false + resolution: + integrity: sha512-UYOadoSIkEI/VrRGSG6qp93rp2WdokiAiNYDfGW5qURAY8GiAQkvMbwNNSDYiVJopqv4gCna7xqf4rrNGp+5AA== + /base-x/3.0.5: + dependencies: + safe-buffer: 5.1.2 + dev: false + resolution: + integrity: sha512-C3picSgzPSLE+jW3tcBzJoGwitOtazb5B+5YmAxZm2ybmTi9LNgAtDO/jjVEBZwHoXmDBZ9m/IELj3elJVRBcA== /base/0.11.2: dependencies: cache-base: 1.0.1 @@ -1620,6 +1654,12 @@ packages: hasBin: true resolution: integrity: sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA== + /browser-request/0.3.3: + dev: false + engines: + '0': node + resolution: + integrity: sha1-ns5bWsqJopkyJC4Yv5M975h2zBc= /browser-resolve/1.11.3: dependencies: resolve: 1.1.7 @@ -1819,6 +1859,12 @@ packages: hasBin: true resolution: integrity: sha512-kMGKs4BTzRWviZ8yru18xBpx+CyHG9eqgRbj9XbE3IMgtczf4aiA0Y1YCpVdvUieKGZ03kolSPXqTcscBCb9qw== + /bs58/4.0.1: + dependencies: + base-x: 3.0.5 + dev: false + resolution: + integrity: sha1-vhYedsNU9veIrkBx9j806MTwpCo= /budo/11.5.0: dependencies: bole: 2.0.0 @@ -2405,6 +2451,12 @@ packages: optional: true resolution: integrity: sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== + /content-type/1.0.4: + dev: false + engines: + node: '>= 0.6' + resolution: + integrity: sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== /convert-source-map/0.3.5: dev: false resolution: @@ -2451,6 +2503,10 @@ packages: resolution: integrity: sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY= tarball: 'http://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz' + /core-js/2.6.5: + dev: false + resolution: + integrity: sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A== /core-util-is/1.0.2: resolution: integrity: sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= @@ -3839,7 +3895,7 @@ packages: dependencies: asynckit: 0.4.0 combined-stream: 1.0.7 - mime-types: 2.1.21 + mime-types: 2.1.22 dev: false engines: node: '>= 0.12' @@ -4491,7 +4547,7 @@ packages: integrity: sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= /har-validator/5.1.3: dependencies: - ajv: 6.6.2 + ajv: 6.10.0 har-schema: 2.0.0 dev: false engines: @@ -4675,7 +4731,7 @@ packages: dependencies: assert-plus: 1.0.0 jsprim: 1.4.1 - sshpk: 1.16.0 + sshpk: 1.16.1 dev: false engines: node: '>=0.8' @@ -5832,6 +5888,12 @@ packages: optional: true resolution: integrity: sha1-X46MkNME7fElMJUaVVSruMXj9VI= + /loglevel/1.6.1: + dev: false + engines: + node: '>= 0.6.0' + resolution: + integrity: sha1-4PyVEztu8nbNyIh82vJKpvFW+Po= /longest/1.0.1: dev: false engines: @@ -5953,6 +6015,22 @@ packages: /math-random/1.0.1: resolution: integrity: sha1-izqsWIuKZuSXXjzepn97sylgH6w= + /matrix-js-sdk/1.0.2: + dependencies: + another-json: 0.2.0 + babel-runtime: 6.26.0 + base-x: 3.0.4 + bluebird: 3.5.3 + browser-request: 0.3.3 + bs58: 4.0.1 + content-type: 1.0.4 + loglevel: 1.6.1 + qs: 6.6.0 + request: 2.88.0 + unhomoglyph: 1.0.2 + dev: false + resolution: + integrity: sha512-4WCBJFSoOLelHi7IUAcVxPQF+gTc/i9NUKZ77qwUfcZVED8VKTIyWZnwpeLgocK5gAOJV9fkAyO5mny9SkZaGg== /md5.js/1.3.5: dependencies: hash-base: 3.0.4 @@ -6085,16 +6163,23 @@ packages: dev: false engines: node: '>= 0.6' + optional: true resolution: integrity: sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg== - /mime-types/2.1.21: + /mime-db/1.38.0: + dev: false + engines: + node: '>= 0.6' + resolution: + integrity: sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg== + /mime-types/2.1.22: dependencies: - mime-db: 1.37.0 + mime-db: 1.38.0 dev: false engines: node: '>= 0.6' resolution: - integrity: sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg== + integrity: sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog== /mime/1.4.1: dev: false hasBin: true @@ -7321,6 +7406,12 @@ packages: node: '>=0.6' resolution: integrity: sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== + /qs/6.6.0: + dev: false + engines: + node: '>=0.6' + resolution: + integrity: sha512-KIJqT9jQJDQx5h5uAVPimw6yVg2SekOKu959OCtktD3FjzbpvaPr8i4zzg07DOMz+igA4W/aNM7OV8H37pFYfA== /query-string/4.3.4: dependencies: object-assign: 4.1.1 @@ -7521,6 +7612,10 @@ packages: dev: false resolution: integrity: sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== + /regenerator-runtime/0.11.1: + dev: false + resolution: + integrity: sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== /regenerator-runtime/0.12.1: dev: false resolution: @@ -7650,7 +7745,7 @@ packages: is-typedarray: 1.0.0 isstream: 0.1.2 json-stringify-safe: 5.0.1 - mime-types: 2.1.21 + mime-types: 2.1.22 oauth-sign: 0.9.0 performance-now: 2.1.0 qs: 6.5.2 @@ -8161,6 +8256,13 @@ packages: node: '>=0.10.0' resolution: integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + /sourceify/0.1.0: + dependencies: + convert-source-map: 1.6.0 + through2: 2.0.5 + dev: false + resolution: + integrity: sha1-C1b+V/lFc1DZJliBCq/afA9EA0w= /sparkles/1.0.1: dev: false engines: @@ -8228,7 +8330,7 @@ packages: node: '>=0.10.0' resolution: integrity: sha1-pWad4StC87HV6D7QPHEEb8SPQe8= - /sshpk/1.16.0: + /sshpk/1.16.1: dependencies: asn1: 0.2.4 assert-plus: 1.0.0 @@ -8244,7 +8346,7 @@ packages: node: '>=0.10.0' hasBin: true resolution: - integrity: sha512-Zhev35/y7hRMcID/upReIvRse+I9SVhyVre/KTJSJQWMz3C3+G+HpO7m1wK/yckEtujKZ7dS4hkVxAnmHaIGVQ== + integrity: sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== /ssri/6.0.1: dependencies: figgy-pudding: 3.5.1 @@ -8987,6 +9089,10 @@ packages: node: '>= 0.10' resolution: integrity: sha1-M52kZGJS0ILcN45wgGcpl1DhG0k= + /unhomoglyph/1.0.2: + dev: false + resolution: + integrity: sha1-1p5fWmocayEZQaCIm4HrqGWVwlM= /unicode-canonical-property-names-ecmascript/1.0.4: dev: false engines: @@ -9546,9 +9652,11 @@ specifiers: gulp-watch: ^5.0.1 jdenticon: ^2.1.1 livereactload: ^4.0.0-beta.2 + matrix-js-sdk: ^1.0.2 react: ^16.6.3 react-dom: ^16.6.3 sanitize-html: ^1.20.0 + sourceify: ^0.1.0 vinyl-buffer: ^1.0.1 vinyl-source-stream: ^2.0.0 webpack: ^4.27.1