Skip to content
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

Rxdb #1987

Closed
wants to merge 46 commits into from
Closed

Rxdb #1987

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
d1d3015
Add TODO_RXDB logging.
raineorshine Mar 21, 2024
524336b
Move thoughtspace from web worker back to main thread.
raineorshine Mar 28, 2024
7e21731
Initial RxDB implementation, add libraries, create a database, and th…
hsmr29 May 31, 2024
c5c0431
add RxDB logic into yjs/thoughspace with a USE_RXDB flag
hsmr29 May 31, 2024
034a355
thoughtspace: improve updateThought and replicateChildren for thought…
hsmr29 Jun 4, 2024
c8d881b
thoughtspace: remove Yjs code related to thoughts where possible, and…
hsmr29 Jun 4, 2024
fd1e9a7
Create RxDB Lexeme schema and collection
hsmr29 Jun 4, 2024
26c5e1f
thoughtspace: Update lexemes to use Rxdb, and remove Yjs code related…
hsmr29 Jun 5, 2024
8c03046
thoughtspcae: Remove Yjs/hocuspocus/y-indexeddb related code
hsmr29 Jun 5, 2024
bbe27ce
thoughtspace: Use findByIds when getting multiple thoughts or lexemes…
hsmr29 Jun 7, 2024
db06da8
Update thoughts schema
hsmr29 Jun 7, 2024
917d921
thoughtspace: remove inserts from replicate thoughts/lexemes
hsmr29 Jun 10, 2024
ee0db2b
RxDB: Create permissions collection
hsmr29 Jun 12, 2024
8f99c8c
Migrate permissions from Yjs to RxDB
hsmr29 Jun 12, 2024
861de97
Remove yjs, y-indexeddb and @hocuspocus/provider libraries
hsmr29 Jun 12, 2024
d7d28cd
workflows: add step to create a rxdb premium access token in a packag…
hsmr29 Jun 13, 2024
e2b3302
Remove TextEncoder from setupTests and ignore duplicate RxDB instance…
hsmr29 Jun 13, 2024
bb35efc
thoughtspace: Remove unnecessary awaits on updateThought
hsmr29 Jun 14, 2024
3b6a526
lexeme schema: Update maxLength for id and contexts
hsmr29 Jun 14, 2024
2680380
- Remove RxDB premium storage-indexeddb adapter
hsmr29 Jun 14, 2024
2f45d9c
useObserveCol: Refactor to use observability directly in the first co…
hsmr29 Jun 16, 2024
41b23ff
Remove unused ThoughtspaceOption properties from thoughtspace
hsmr29 Jun 17, 2024
82c1ace
thoughtspace:
hsmr29 Jun 17, 2024
916f839
Rename document types in RxDB collections using a new nomenclature
hsmr29 Jun 17, 2024
765a349
Add freeThought back to the thoughtspace api
hsmr29 Jun 17, 2024
a1f13d3
- Create RxDB test database with RxStorageMemory storage
hsmr29 Jun 18, 2024
e2f8e49
thoughtspace: Use collection.remove method instead of destroying data…
hsmr29 Jun 18, 2024
df6df7c
Add rxdb-premium script to build the project using the IndexedDB storage
hsmr29 Jun 24, 2024
0014df9
Rename build premium script
hsmr29 Jun 24, 2024
9e2890e
rxdb-premium script: Check if rxdb-premium library is already installed.
hsmr29 Jun 24, 2024
cecfc19
thoughtspace: Simplify and mark as deprecated the following functions:
hsmr29 Jun 28, 2024
30bdd50
thoughtspace: Add "await" to the rxdb calls in updateThought function…
hsmr29 Jun 28, 2024
beca6a4
thoughtspace: Update comments and minor refactor to lexeme functions
hsmr29 Jun 28, 2024
1535357
Use Dexie storage for testing as well
hsmr29 Jun 29, 2024
8ff2763
Fix tests for Dexie Storage, Remove fakeTimer from vitest
hsmr29 Jun 29, 2024
67a0b47
Add random number to rxdb database name on test environment
hsmr29 Jul 3, 2024
502f4a9
Update RxDB library to latest version
hsmr29 Jul 3, 2024
fcd00ab
Skip failing test on CI
hsmr29 Jul 3, 2024
d169490
rxdb-premium: Add summary comment for documentation purposes
hsmr29 Jul 11, 2024
c529d03
ColorPicker: Add comment to explain why we disabled the tests in this…
hsmr29 Jul 11, 2024
c5b5ad9
useRxCollection: rename useObserveCol hook to useRxCollection
hsmr29 Jul 11, 2024
443c309
thoughtspace: remove unnecessary console.info
hsmr29 Jul 11, 2024
36f6ad3
Update RxDB from 15.26.0 to 15.28.0
hsmr29 Jul 13, 2024
1304543
thoughspace: bulk update/delete for thoughts and lexemes
hsmr29 Jul 22, 2024
2fe63bb
thoughtspace: add Rx observers for thoughts/lexemes
hsmr29 Jul 22, 2024
29a9b95
Add RxDB WebRTC replication:
hsmr29 Jul 22, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .env.development
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ VITE_FEEDBACK_URL=https://us-central1-em-search-test.cloudfunctions.net/sendFeed
VITE_WEBSOCKET_HOST=localhost
VITE_WEBSOCKET_PORT=3001

# WEBRTC SERVER
VITE_WEBRTC_HOST=localhost
VITE_WEBRTC_PORT=3002

# CAPACITOR
# Local IP addresses should only be defined in .env.development.local so that they are not checked into version control.
CAPACITOR_SERVER_URL=
Expand Down
4 changes: 4 additions & 0 deletions .env.production
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,9 @@ VITE_FEEDBACK_URL=https://us-central1-em-proto.cloudfunctions.net/sendFeedbackEm
VITE_WEBSOCKET_HOST=em-staging-sa2jm.ondigitalocean.app
VITE_WEBSOCKET_PORT=

# WEBRTC SERVER
VITE_WEBRTC_HOST=
VITE_WEBRTC_PORT=

# AI SERVER
VITE_AI_URL=https://em-staging-sa2jm.ondigitalocean.app/ai
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"cap:sync:prod": "npm run build && NODE_ENV=production cap sync",
"start": "vite --host --port 3000",
"build": "vite build",
"build:premium": "node scripts/rxdb-premium.js",
"clean": "rm -rf ./node_modules/.cache",
"docs": "typedoc --options typedoc.json",
"deploy:major": "npm run lint && npm version major && npm run build && firebase deploy --only hosting",
Expand Down Expand Up @@ -77,7 +78,6 @@
"@capacitor/status-bar": "^4.1.1",
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5",
"@hocuspocus/provider": "^2.13.5",
"@mui/material": "^5.15.20",
"algoliasearch": "^4.24.0",
"axios": "^1.7.2",
Expand Down Expand Up @@ -120,6 +120,8 @@
"redux-devtools-extension": "^2.13.9",
"redux-thunk": "^2.4.2",
"reselect": "^5.1.1",
"rxdb": "^15.28.1",
"rxjs": "^7.8.1",
"text-block-parser": "^1.1.1",
"truncate-html": "^1.1.1",
"ts-key-enum": "^2.0.12",
Expand All @@ -130,9 +132,7 @@
"workbox-routing": "^7.1.0",
"workbox-strategies": "^7.1.0",
"xhtml-purifier": "^0.4.1",
"y-indexeddb": "https://github.com/raineorshine/y-indexeddb#y-indexeddb-multiplex",
"yallist": "^5.0.0",
"yjs": "^13.6.17"
"yallist": "^5.0.0"
},
"devDependencies": {
"@babel/core": "^7.24.7",
Expand Down
2 changes: 2 additions & 0 deletions rxdb-server/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/node_modules
/build
27 changes: 27 additions & 0 deletions rxdb-server/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"name": "rxdb-server",
"version": "1.0.0",
"main": "main",
"scripts": {
"build": "rm -rf build ; npx tsc",
"kill": "pm2 kill",
"start": "pm2 start pm2.config.js",
"logs": "pm2 logs",
"monit": "pm2 monit",
"restart": "pm2 restart pm2.config.js",
"status": "pm2 status pm2.config.js",
"stop": "pm2 stop pm2.config.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"devDependencies": {
"pm2": "^5.4.2",
"typescript": "^5.5.3"
},
"dependencies": {
"rxdb": "15.27.0",
"ws": "^8.18.0"
}
}
13 changes: 13 additions & 0 deletions rxdb-server/pm2.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// pm2 configuration
// https://pm2.keymetrics.io/docs/usage/application-declaration/

module.exports = {
apps: [
{
name: 'server',
script: './build/index.js',
time: true,
wait_ready: true,
},
],
}
172 changes: 172 additions & 0 deletions rxdb-server/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
import { getFromMapOrCreate, promiseWait, randomCouchString } from 'rxdb'
import { type PeerMessage, SIMPLE_PEER_PING_INTERVAL } from 'rxdb/plugins/replication-webrtc'
import type { ServerOptions, WebSocket } from 'ws'

const PORT = 3002 // TODO - Get from env

export const PEER_ID_LENGTH = 12
export type ServerPeer = {
id: string
socket: WebSocket
rooms: Set<string>
lastPing: number
}

/**
* Starts a WebRTC signaling server
* that can be used in tests.
*/
export async function startSignalingServerSimplePeer(serverOptions: ServerOptions) {
const { WebSocketServer } = await import('ws')
const wss = new WebSocketServer(serverOptions)

const peerById = new Map<string, ServerPeer>()
const peersByRoom = new Map<string, Set<string>>()

let serverClosed = false
wss.on('close', () => {
serverClosed = true
peerById.clear()
peersByRoom.clear()
})

/**
* Clients can disconnect without telling that to the
* server. Therefore we have to automatically disconnect clients that
* have not send a ping message in the last 2 minutes.
*/
;(async () => {
// eslint-disable-next-line no-unmodified-loop-condition
while (!serverClosed) {
await promiseWait(1000 * 5)
const minTime = Date.now() - SIMPLE_PEER_PING_INTERVAL
Array.from(peerById.values()).forEach(peer => {
if (peer.lastPing < minTime) {
disconnectSocket(peer.id, 'no ping for 2 minutes')
}
})
}
})()

/** Disconnect a peer. */
function disconnectSocket(peerId: string, reason: string) {
const peer = peerById.get(peerId)
if (peer) {
peer.socket.close && peer.socket.close(undefined, reason)
peer.rooms.forEach(roomId => {
const room = peersByRoom.get(roomId)
room?.delete(peerId)
if (room && room.size === 0) {
peersByRoom.delete(roomId)
}
})
}
peerById.delete(peerId)
}

wss.on('connection', function (ws) {
/**
* PeerID is created by the server to prevent malicious
* actors from falsy claiming other peoples ids.
*/
const peerId = randomCouchString(PEER_ID_LENGTH)
const peer: ServerPeer = {
id: peerId,
socket: ws,
rooms: new Set(),
lastPing: Date.now(),
}
peerById.set(peerId, peer)

sendMessage(ws, { type: 'init', yourPeerId: peerId })

ws.on('error', err => {
console.error('SERVER ERROR:', err)
disconnectSocket(peerId, 'socket errored')
})
ws.on('close', () => {
disconnectSocket(peerId, 'socket disconnected')
})

ws.on('message', msgEvent => {
peer.lastPing = Date.now()
const message = JSON.parse(msgEvent.toString())
const type = message.type
switch (type) {
case 'join': {
const roomId = message.room
if (!validateIdString(roomId) || !validateIdString(peerId)) {
disconnectSocket(peerId, 'invalid ids')
return
}

if (peer.rooms.has(peerId)) {
return
}
peer.rooms.add(roomId)

const room = getFromMapOrCreate(peersByRoom, message.room, () => new Set())

room.add(peerId)

// tell everyone about new room state
room.forEach(otherPeerId => {
const otherPeer = peerById.get(otherPeerId)
if (otherPeer) {
sendMessage(otherPeer.socket, {
type: 'joined',
otherPeerIds: Array.from(room),
})
}
})
break
}
case 'signal': {
if (message.senderPeerId !== peerId) {
disconnectSocket(peerId, 'spoofed sender')
return
}
const receiver = peerById.get(message.receiverPeerId)
if (receiver) {
sendMessage(receiver.socket, message)
}
break
}
case 'ping':
break
default:
disconnectSocket(peerId, 'unknown message type ' + type)
}
})
})

return {
port: serverOptions.port,
server: wss,
localUrl: 'ws://localhost:' + serverOptions.port,
}
}

/** Send a message to a peer. */
function sendMessage(ws: WebSocket, message: PeerMessage) {
const msgString = JSON.stringify(message)
ws.send(msgString)
}

/** Validate that a string is a valid id. */
function validateIdString(roomId: string): boolean {
if (typeof roomId === 'string' && roomId.length > 5 && roomId.length < 100) {
return true
} else {
return false
}
}

/** Main. */
async function main() {
await startSignalingServerSimplePeer({
port: PORT,
})
}

main()
9 changes: 9 additions & 0 deletions rxdb-server/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "../tsconfig.json",
"include": ["src/index.ts"],
"compilerOptions": {
"module": "commonjs",
"noEmit": false,
"outDir": "build"
}
}
Loading
Loading