Added websocket presence.

This commit is contained in:
Michael Mainguy 2024-06-14 09:38:16 -05:00
parent 4e1436b0cc
commit d08e86e92f
9 changed files with 533 additions and 48 deletions

203
package-lock.json generated
View File

@ -1,12 +1,12 @@
{ {
"name": "immersive", "name": "immersive",
"version": "0.0.7", "version": "0.0.8-13",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "immersive", "name": "immersive",
"version": "0.0.7", "version": "0.0.8-13",
"dependencies": { "dependencies": {
"@babylonjs/core": "^7.9.0", "@babylonjs/core": "^7.9.0",
"@babylonjs/gui": "^7.9.0", "@babylonjs/gui": "^7.9.0",
@ -29,6 +29,7 @@
"hls.js": "^1.1.4", "hls.js": "^1.1.4",
"js-crypto-aes": "1.0.6", "js-crypto-aes": "1.0.6",
"loglevel": "^1.9.1", "loglevel": "^1.9.1",
"meaningful-string": "^1.4.0",
"peer-lite": "2.0.2", "peer-lite": "2.0.2",
"pouchdb": "^8.0.1", "pouchdb": "^8.0.1",
"pouchdb-find": "^8.0.1", "pouchdb-find": "^8.0.1",
@ -38,7 +39,9 @@
"rfc4648": "^1.5.3", "rfc4648": "^1.5.3",
"round": "^2.0.1", "round": "^2.0.1",
"uint8-to-b64": "^1.0.2", "uint8-to-b64": "^1.0.2",
"uuid": "^9.0.1" "uuid": "^9.0.1",
"websocket": "^1.0.34",
"websocket-ts": "^2.1.5"
}, },
"devDependencies": { "devDependencies": {
"@types/dom-to-image": "^2.6.7", "@types/dom-to-image": "^2.6.7",
@ -1169,6 +1172,28 @@
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
}, },
"node_modules/bufferutil": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz",
"integrity": "sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==",
"hasInstallScript": true,
"dependencies": {
"node-gyp-build": "^4.3.0"
},
"engines": {
"node": ">=6.14.2"
}
},
"node_modules/bufferutil/node_modules/node-gyp-build": {
"version": "4.8.1",
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz",
"integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==",
"bin": {
"node-gyp-build": "bin.js",
"node-gyp-build-optional": "optional.js",
"node-gyp-build-test": "build-test.js"
}
},
"node_modules/cac": { "node_modules/cac": {
"version": "6.7.14", "version": "6.7.14",
"resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
@ -1270,6 +1295,18 @@
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
}, },
"node_modules/d": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz",
"integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==",
"dependencies": {
"es5-ext": "^0.10.64",
"type": "^2.7.2"
},
"engines": {
"node": ">=0.12"
}
},
"node_modules/debug": { "node_modules/debug": {
"version": "4.3.4", "version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@ -1386,6 +1423,43 @@
"errno": "cli.js" "errno": "cli.js"
} }
}, },
"node_modules/es5-ext": {
"version": "0.10.64",
"resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz",
"integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==",
"hasInstallScript": true,
"dependencies": {
"es6-iterator": "^2.0.3",
"es6-symbol": "^3.1.3",
"esniff": "^2.0.1",
"next-tick": "^1.1.0"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/es6-iterator": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
"integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
"dependencies": {
"d": "1",
"es5-ext": "^0.10.35",
"es6-symbol": "^3.1.1"
}
},
"node_modules/es6-symbol": {
"version": "3.1.4",
"resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz",
"integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==",
"dependencies": {
"d": "^1.0.2",
"ext": "^1.7.0"
},
"engines": {
"node": ">=0.12"
}
},
"node_modules/esbuild": { "node_modules/esbuild": {
"version": "0.20.2", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz",
@ -1424,6 +1498,20 @@
"@esbuild/win32-x64": "0.20.2" "@esbuild/win32-x64": "0.20.2"
} }
}, },
"node_modules/esniff": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz",
"integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==",
"dependencies": {
"d": "^1.0.1",
"es5-ext": "^0.10.62",
"event-emitter": "^0.3.5",
"type": "^2.7.2"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/estree-walker": { "node_modules/estree-walker": {
"version": "3.0.3", "version": "3.0.3",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
@ -1433,6 +1521,15 @@
"@types/estree": "^1.0.0" "@types/estree": "^1.0.0"
} }
}, },
"node_modules/event-emitter": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
"integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==",
"dependencies": {
"d": "1",
"es5-ext": "~0.10.14"
}
},
"node_modules/event-target-shim": { "node_modules/event-target-shim": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
@ -1472,6 +1569,14 @@
"url": "https://github.com/sindresorhus/execa?sponsor=1" "url": "https://github.com/sindresorhus/execa?sponsor=1"
} }
}, },
"node_modules/ext": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz",
"integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==",
"dependencies": {
"type": "^2.7.2"
}
},
"node_modules/fast-glob": { "node_modules/fast-glob": {
"version": "3.3.2", "version": "3.3.2",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
@ -1777,6 +1882,11 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="
},
"node_modules/isarray": { "node_modules/isarray": {
"version": "0.0.1", "version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
@ -2041,6 +2151,11 @@
"@jridgewell/sourcemap-codec": "^1.4.15" "@jridgewell/sourcemap-codec": "^1.4.15"
} }
}, },
"node_modules/meaningful-string": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/meaningful-string/-/meaningful-string-1.4.0.tgz",
"integrity": "sha512-i95AQGuJcVR5mslLf60GyxRIr7EazCgXoR+pFAZCdySAMJ5G3PiLq/dsyv74zKOnLieF1ipeFEp86IMUvcIO3Q=="
},
"node_modules/merge-stream": { "node_modules/merge-stream": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
@ -2141,6 +2256,11 @@
"resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz", "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz",
"integrity": "sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==" "integrity": "sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg=="
}, },
"node_modules/next-tick": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz",
"integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ=="
},
"node_modules/node-fetch": { "node_modules/node-fetch": {
"version": "2.6.7", "version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
@ -2959,6 +3079,11 @@
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
}, },
"node_modules/type": {
"version": "2.7.3",
"resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz",
"integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ=="
},
"node_modules/type-detect": { "node_modules/type-detect": {
"version": "4.0.8", "version": "4.0.8",
"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
@ -2968,6 +3093,14 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/typedarray-to-buffer": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
"integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
"dependencies": {
"is-typedarray": "^1.0.0"
}
},
"node_modules/typescript": { "node_modules/typescript": {
"version": "4.9.5", "version": "4.9.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
@ -3017,6 +3150,28 @@
"requires-port": "^1.0.0" "requires-port": "^1.0.0"
} }
}, },
"node_modules/utf-8-validate": {
"version": "5.0.10",
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz",
"integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==",
"hasInstallScript": true,
"dependencies": {
"node-gyp-build": "^4.3.0"
},
"engines": {
"node": ">=6.14.2"
}
},
"node_modules/utf-8-validate/node_modules/node-gyp-build": {
"version": "4.8.1",
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz",
"integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==",
"bin": {
"node-gyp-build": "bin.js",
"node-gyp-build-optional": "optional.js",
"node-gyp-build-test": "build-test.js"
}
},
"node_modules/util-deprecate": { "node_modules/util-deprecate": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@ -3196,6 +3351,40 @@
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
}, },
"node_modules/websocket": {
"version": "1.0.35",
"resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.35.tgz",
"integrity": "sha512-/REy6amwPZl44DDzvRCkaI1q1bIiQB0mEFQLUrhz3z2EK91cp3n72rAjUlrTP0zV22HJIUOVHQGPxhFRjxjt+Q==",
"dependencies": {
"bufferutil": "^4.0.1",
"debug": "^2.2.0",
"es5-ext": "^0.10.63",
"typedarray-to-buffer": "^3.1.5",
"utf-8-validate": "^5.0.2",
"yaeti": "^0.0.6"
},
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/websocket-ts": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/websocket-ts/-/websocket-ts-2.1.5.tgz",
"integrity": "sha512-rCNl9w6Hsir1azFm/pbjBEFzLD/gi7Th5ZgOxMifB6STUfTSovYAzryWw0TRvSZ1+Qu1Z5Plw4z42UfTNA9idA=="
},
"node_modules/websocket/node_modules/debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/websocket/node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"node_modules/whatwg-url": { "node_modules/whatwg-url": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
@ -3257,6 +3446,14 @@
"node": ">=0.4" "node": ">=0.4"
} }
}, },
"node_modules/yaeti": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz",
"integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==",
"engines": {
"node": ">=0.10.32"
}
},
"node_modules/yocto-queue": { "node_modules/yocto-queue": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz",

View File

@ -11,6 +11,7 @@
"test": "vitest", "test": "vitest",
"build": "node versionBump.js && vite build", "build": "node versionBump.js && vite build",
"preview": "vite preview", "preview": "vite preview",
"socket": "node server/server.js",
"serve": "node server.js", "serve": "node server.js",
"serverBuild": "cd server && tsc", "serverBuild": "cd server && tsc",
"havok": "cp ./node_modules/@babylonjs/havok/lib/esm/HavokPhysics.wasm ./node_modules/.vite/deps" "havok": "cp ./node_modules/@babylonjs/havok/lib/esm/HavokPhysics.wasm ./node_modules/.vite/deps"
@ -46,7 +47,10 @@
"js-crypto-aes": "1.0.6", "js-crypto-aes": "1.0.6",
"events": "^3.3.0", "events": "^3.3.0",
"hash-wasm": "4.11.0", "hash-wasm": "4.11.0",
"uint8-to-b64": "^1.0.2" "uint8-to-b64": "^1.0.2",
"meaningful-string": "^1.4.0",
"websocket-ts": "^2.1.5",
"websocket": "^1.0.34"
}, },
"devDependencies": { "devDependencies": {
"@types/dom-to-image": "^2.6.7", "@types/dom-to-image": "^2.6.7",

114
server/server.js Normal file
View File

@ -0,0 +1,114 @@
import websocket from "websocket";
import http from "http";
import {sha512} from "hash-wasm";
import log from "loglevel";
async function start() {
const logger = log.getLogger("server");
logger.setLevel("DEBUG", false);
const WebSocketServer = websocket.server;
//const http = require('http');
//const sha512 = require('hash-wasm').sha512;
const connections = new Map();
const server = http.createServer(function (request, response) {
logger.info((new Date()) + ' Received request for ' + request.url);
response.writeHead(404);
response.end();
});
server.listen(8080, function () {
logger.info((new Date()) + ' Server is listening on port 8080');
});
const wsServer = new WebSocketServer({
httpServer: server,
// You should not use autoAcceptConnections for production
// applications, as it defeats all standard cross-origin protection
// facilities built into the protocol and the browser. You should
// *always* verify the connection's origin and decide whether or not
// to accept it.
autoAcceptConnections: false
});
function originIsAllowed(origin) {
return origin.indexOf('deepdiagram') > -1;
}
wsServer.on('request', async (request) => {
if (!originIsAllowed(request.origin)) {
// Make sure we only accept requests from an allowed origin
request.reject();
logger.error((new Date()) + ' Connection from origin ' + request.origin + ' rejected.');
return;
}
try {
const connection = request.accept('echo-protocol', request.origin);
const hash = await sha512(connection.socket.remoteAddress + '-' + connection.socket.remotePort);
connections.set(hash, {connection: connection, db: null});
logger.info((new Date()) + ' Connection accepted.', connections.length);
connections.forEach((conn, key) => {
if (key != hash) {
conn.connection.sendUTF('{ "type": "newconnect", "netAttr": "' + hash + '" }');
}
});
connection.on('message', function (message) {
logger.debug(message);
if (message.type === 'utf8') {
logger.debug('Received Message: ' + message.utf8Data);
connections.forEach((conn, index) => {
const envelope = JSON.parse(message.utf8Data);
if (index !== hash) {
if (envelope.db === conn.db) {
envelope.netAddr = hash;
conn.connection.sendUTF(JSON.stringify(envelope));
}
} else {
if (!conn.db && envelope.db) {
conn.db = envelope.db;
logger.debug('DB set to ' + envelope.db);
}
}
});
//connection.sendUTF(message.utf8Data);
} else if (message.type === 'binary') {
logger.debug('Received Binary Message of ' + message.binaryData.length + ' bytes');
connections.forEach((conn, index) => {
if (index !== hash) {
conn.connection.sendBytes(message.utf8Data);
}
});
}
});
connection.on('close', function (reasonCode, description) {
connections.delete(hash);
connections.forEach((conn, index) => {
conn.connection.sendUTF('{ "type": "close", "netAddr": "' + hash + '" }');
});
});
connection.on('error', function (reasonCode, description) {
connections.delete(hash);
connections.forEach((conn, index) => {
conn.connection.sendUTF('{ "type": "error", "netAddr": "' + hash + '" }');
});
logger.info((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.', connections.length);
});
setInterval(() => {
const message = `{ "count": ${connections.size} }`
logger.debug(message);
connection.sendUTF(message);
}, 10000);
} catch (err) {
console.log(err);
}
});
}
start();

View File

@ -9,6 +9,8 @@ import {DiagramMenuManager} from "./diagramMenuManager";
import {DiagramEventObserverMask} from "./types/diagramEventObserverMask"; import {DiagramEventObserverMask} from "./types/diagramEventObserverMask";
import {DiagramObject} from "./diagramObject"; import {DiagramObject} from "./diagramObject";
import {getMe} from "../util/me"; import {getMe} from "../util/me";
import {UserModelType} from "../users/userTypes";
import {vectoxys} from "./functions/vectorConversion";
export class DiagramManager { export class DiagramManager {
@ -17,10 +19,14 @@ export class DiagramManager {
private readonly _controllers: Controllers; private readonly _controllers: Controllers;
private readonly _diagramEntityActionManager: ActionManager; private readonly _diagramEntityActionManager: ActionManager;
public readonly onDiagramEventObservable: Observable<DiagramEvent> = new Observable(); public readonly onDiagramEventObservable: Observable<DiagramEvent> = new Observable();
public readonly onUserEventObservable: Observable<UserModelType> = new Observable();
private readonly _diagramMenuManager: DiagramMenuManager; private readonly _diagramMenuManager: DiagramMenuManager;
private readonly _scene: Scene; private readonly _scene: Scene;
private readonly _diagramObjects: Map<string, DiagramObject> = new Map<string, DiagramObject>(); private readonly _diagramObjects: Map<string, DiagramObject> = new Map<string, DiagramObject>();
private readonly _me: string; private readonly _me: string;
private _moving: number = 10;
private _i: number = 0;
constructor() { constructor() {
this._me = getMe(); this._me = getMe();
this._scene = DefaultScene.Scene; this._scene = DefaultScene.Scene;
@ -30,6 +36,45 @@ export class DiagramManager {
this._diagramEntityActionManager = buildEntityActionManager(this._controllers); this._diagramEntityActionManager = buildEntityActionManager(this._controllers);
this.onDiagramEventObservable.add(this.onDiagramEvent, DiagramEventObserverMask.FROM_DB, true, this); this.onDiagramEventObservable.add(this.onDiagramEvent, DiagramEventObserverMask.FROM_DB, true, this);
this.onUserEventObservable.add((user) => {
if (user.id != this._me) {
this._logger.debug('user event', user);
}
});
window.setInterval(() => {
this._i++;
const platform = this._scene.getMeshByName('platform');
if (!platform || !platform.physicsBody) {
return;
}
if (platform.physicsBody) {
if ((this._i % this._moving) == 0) {
this.onUserEventObservable.notifyObservers(
{
id: this._me,
name: 'me',
type: 'user',
base: {
position: vectoxys(platform.absolutePosition),
rotation: vectoxys(platform.absoluteRotationQuaternion.toEulerAngles()),
velocity: vectoxys(platform.physicsBody.getLinearVelocity())
},
}
);
}
if (platform.physicsBody.getLinearVelocity().length() > 0.01) {
this._moving = 1;
} else {
this._moving = 10;
}
}
}, 100);
document.addEventListener('uploadImage', (event: CustomEvent) => { document.addEventListener('uploadImage', (event: CustomEvent) => {
const diagramEntity: DiagramEntity = { const diagramEntity: DiagramEntity = {
template: '#image-template', template: '#image-template',
@ -88,6 +133,7 @@ export class DiagramManager {
public addObject(diagramObject: DiagramObject) { public addObject(diagramObject: DiagramObject) {
this._diagramObjects.set(diagramObject.diagramEntity.id, diagramObject); this._diagramObjects.set(diagramObject.diagramEntity.id, diagramObject);
} }
public get config(): AppConfig { public get config(): AppConfig {
return this._config; return this._config;
} }

View File

@ -1,12 +1,10 @@
import log from "loglevel"; import log from "loglevel";
import {DiagramEntity} from "../../diagram/types/diagramEntity"; import {DiagramEntity} from "../../diagram/types/diagramEntity";
import {Observable} from "@babylonjs/core"; import {Observable} from "@babylonjs/core";
import {UserModelType} from "../../users/userTypes";
import {Encryption} from "../encryption"; import {Encryption} from "../encryption";
import {DiagramEventObserverMask} from "../../diagram/types/diagramEventObserverMask"; import {DiagramEventObserverMask} from "../../diagram/types/diagramEventObserverMask";
export async function syncDoc(info: any, onDBRemoveObservable: Observable<DiagramEntity>, onDBUpdateObservable: Observable<DiagramEntity>, export async function syncDoc(info: any, onDBRemoveObservable: Observable<DiagramEntity>, onDBUpdateObservable: Observable<DiagramEntity>,
onUserObservable: Observable<UserModelType>,
encryption: Encryption, key: string) { encryption: Encryption, key: string) {
const logger = log.getLogger('syncDoc'); const logger = log.getLogger('syncDoc');
logger.debug(info); logger.debug(info);

View File

@ -12,27 +12,37 @@ import {checkDb} from "./functions/checkDb";
import {UserModelType} from "../users/userTypes"; import {UserModelType} from "../users/userTypes";
import {getMe} from "../util/me"; import {getMe} from "../util/me";
import {Encryption} from "./encryption"; import {Encryption} from "./encryption";
import {Presence} from "./presence";
type PasswordEvent = {
detail: string;
}
export class PouchdbPersistenceManager { export class PouchdbPersistenceManager {
private _logger: Logger = log.getLogger('PouchdbPersistenceManager'); private _logger: Logger = log.getLogger('PouchdbPersistenceManager');
onDBEntityUpdateObservable: Observable<DiagramEntity> = new Observable<DiagramEntity>(); onDBEntityUpdateObservable: Observable<DiagramEntity> = new Observable<DiagramEntity>();
onDBEntityRemoveObservable: Observable<DiagramEntity> = new Observable<DiagramEntity>(); onDBEntityRemoveObservable: Observable<DiagramEntity> = new Observable<DiagramEntity>();
onUserObservable: Observable<UserModelType> = new Observable<UserModelType>();
private db: PouchDB; private db: PouchDB;
private remote: PouchDB; private remote: PouchDB;
private user: string; private user: string;
private _encryption = new Encryption(); private _encryption = new Encryption();
private _encKey = null; private _encKey = null;
private _diagramManager: DiagramManager;
constructor() { constructor() {
document.addEventListener('passwordset', (evt) => { document.addEventListener('passwordset', (evt) => {
this._encKey = evt.detail || null; this._encKey = ((evt as unknown) as PasswordEvent).detail || null;
if (this._encKey && typeof (this._encKey) == 'string') { if (this._encKey && typeof (this._encKey) == 'string') {
this.initialize(); this.initialize().then(() => {
this._logger.debug('Initialized');
});
} }
console.log(evt); console.log(evt);
}); });
} }
public setDiagramManager(diagramManager: DiagramManager) { public setDiagramManager(diagramManager: DiagramManager) {
this._diagramManager = diagramManager;
diagramManager.onDiagramEventObservable.add((evt) => { diagramManager.onDiagramEventObservable.add((evt) => {
this._logger.debug(evt); this._logger.debug(evt);
switch (evt.type) { switch (evt.type) {
@ -61,11 +71,7 @@ export class PouchdbPersistenceManager {
} }
}); });
this.onUserObservable.add((evt) => {
if (evt.id == getMe()) {
this.updateUser(evt);
}
});
this.onDBEntityRemoveObservable.add((entity) => { this.onDBEntityRemoveObservable.add((entity) => {
this._logger.debug(entity); this._logger.debug(entity);
@ -74,21 +80,6 @@ export class PouchdbPersistenceManager {
}); });
} }
private async updateUser(user: UserModelType) {
try {
const doc = await this.db.get(user.id);
if (doc) {
const newDoc = {...doc, ...user};
await this.db.put(newDoc);
}
} catch (err) {
if (err.status == 404) {
await this.db.put({...user, _id: user.id});
} else {
this._logger.error(err);
}
}
}
public async remove(id: string) { public async remove(id: string) {
if (!id) { if (!id) {
return; return;
@ -252,26 +243,23 @@ export class PouchdbPersistenceManager {
salt = dbEntity.doc.encrypted.salt; salt = dbEntity.doc.encrypted.salt;
} }
const decrypted = await this._encryption.decryptToObject(dbEntity.doc.encrypted.encrypted, dbEntity.doc.encrypted.iv); const decrypted = await this._encryption.decryptToObject(dbEntity.doc.encrypted.encrypted, dbEntity.doc.encrypted.iv);
if (decrypted.type == 'user') {
this.onUserObservable.notifyObservers(decrypted); if (decrypted.id != 'metadata') {
} else { this.onDBEntityUpdateObservable.notifyObservers(decrypted, DiagramEventObserverMask.FROM_DB);
if (decrypted.id != 'metadata') {
this.onDBEntityUpdateObservable.notifyObservers(decrypted, DiagramEventObserverMask.FROM_DB);
}
} }
} else { } else {
if (dbEntity.type == 'user') {
this.onUserObservable.notifyObservers(dbEntity.doc); if (dbEntity.id != 'metadata') {
} else { this.onDBEntityUpdateObservable.notifyObservers(dbEntity.doc, DiagramEventObserverMask.FROM_DB);
if (dbEntity.id != 'metadata') {
this.onDBEntityUpdateObservable.notifyObservers(dbEntity.doc, DiagramEventObserverMask.FROM_DB);
}
} }
} }
} }
} if (clear) {
if (clear) { localStorage.removeItem('clearLocal');
localStorage.removeItem('clearLocal'); }
} }
} catch (err) { } catch (err) {
switch (err.message) { switch (err.message) {
@ -335,10 +323,14 @@ export class PouchdbPersistenceManager {
{auth: {username: remoteUserName, password: password}, skip_setup: true}); {auth: {username: remoteUserName, password: password}, skip_setup: true});
const dbInfo = await this.remote.info(); const dbInfo = await this.remote.info();
this._logger.debug(dbInfo); this._logger.debug(dbInfo);
const presence: Presence = new Presence(getMe(), remoteDbName);
this._diagramManager.onUserEventObservable.add((user: UserModelType) => {
this._logger.debug(user);
presence.sendUser(user);
}, -1, false, this);
this.db.sync(this.remote, {live: true, retry: true}) this.db.sync(this.remote, {live: true, retry: true})
.on('change', (info) => { .on('change', (info) => {
syncDoc(info, this.onDBEntityRemoveObservable, this.onDBEntityUpdateObservable, this.onUserObservable, this._encryption, this._encKey); syncDoc(info, this.onDBEntityRemoveObservable, this.onDBEntityUpdateObservable, this._encryption, this._encKey);
}) })
.on('active', (info) => { .on('active', (info) => {
this._logger.debug('sync active', info) this._logger.debug('sync active', info)

134
src/integration/presence.ts Normal file
View File

@ -0,0 +1,134 @@
import {RingQueue, Websocket, WebsocketBuilder} from "websocket-ts";
import {getMe} from "../util/me";
import {UserModelType} from "../users/userTypes";
import log, {Logger} from "loglevel";
import {DefaultScene} from "../defaultScene";
import {Color3, MeshBuilder, StandardMaterial, TransformNode} from "@babylonjs/core";
import {xyztovec} from "../diagram/functions/vectorConversion";
export class Presence {
private _logger: Logger = log.getLogger("Presence");
private _ws: Websocket;
private _id: string;
constructor(id: string = null, db: string = null) {
this._db = db;
if (id == null) {
const localMe = getMe();
if (localMe != null) {
this._id = localMe;
}
} else {
this._id = id;
}
if (this._id != null) {
this.build();
} else {
console.error('no user id found');
}
}
private _db: string;
public set db(db: string) {
this._db = db;
}
public sendUser(user: UserModelType) {
if (this._ws) {
try {
this._ws.send(JSON.stringify({'type': 'user', 'id': this._id, 'db': this._db, 'user': user}));
} catch (err) {
this._logger.error(err);
}
}
}
private build() {
try {
this._ws = new WebsocketBuilder("wss://presence.deepdiagram.com:443/")
.withBuffer(new RingQueue(2))
.onOpen(() => {
const me = {'type': 'connect', id: this._id};
this._ws.send(JSON.stringify(me));
})
.onClose(() => this._logger.debug("closed"))
.onError(() => this._logger.debug("error"))
.onMessage((i, ev) => {
this._logger.debug(i);
this._logger.debug(ev.data);
try {
const data = JSON.parse(ev.data);
switch (data.type) {
case 'connect':
break;
case 'ping':
if (data.db && data.id != this._id) {
this._ws.send(JSON.stringify({'type': 'pong', 'id': this._id, 'db': this._db}));
}
break;
case'close':
const scene = DefaultScene.Scene;
const user = scene.getTransformNodeById(data.netAddr);
if (user) {
user.dispose(false, true)
}
break;
case 'pong':
this._logger.debug(data);
break;
case 'user':
if (data.user) {
if (data.user.id) {
const scene = DefaultScene.Scene;
if (scene) {
const user = scene.getTransformNodeById(data.netAddr);
if (user) {
user.position = xyztovec(data.user.base.position);
user.rotation = xyztovec(data.user.base.rotation);
} else {
this._logger.warn('user not found', data.user);
const newUser = MeshBuilder.CreateDisc(data.user.id, {radius: 0.3}, scene);
const node = new TransformNode(data.netAddr, scene);
const material = new StandardMaterial(data.user.id + 'mat', scene);
material.diffuseColor = new Color3(0, 0, 1);
material.backFaceCulling = false;
newUser.material = material;
newUser.parent = node;
newUser.rotation.x = Math.PI / 2;
newUser.position.y = 0.01;
node.position = xyztovec(data.user.base.position);
node.rotation = xyztovec(data.user.base.rotation);
}
}
this._logger.debug('user update', data.user);
}
}
}
} catch (e) {
console.error(e);
}
this._logger.debug("message")
})
.onRetry(() => this._logger.debug("retry"))
.onReconnect(() => this._logger.debug("reconnect"))
.withProtocols("echo-protocol")
.build();
window.setInterval(() => {
this._ws.send(JSON.stringify({'type': 'ping', 'id': this._id, db: this._db}));
}, 15000, this);
//this._ws.send(this._id);
} catch (err) {
this._logger.error(err);
return;
}
}
}

View File

@ -10,7 +10,8 @@ export type UserModelType = {
state?: string, state?: string,
base: { base: {
position: XYZType, position: XYZType,
rotation: XYZType rotation: XYZType,
velocity?: XYZType
} }
head?: { head?: {
position: XYZType, position: XYZType,

View File

@ -17,7 +17,6 @@ import {Introduction} from "./tutorial/introduction";
const webGpu = false; const webGpu = false;
log.setLevel('error', false); log.setLevel('error', false);
log.getLogger('Handle').setLevel('debug');
const canvas = (document.querySelector('#gameCanvas') as HTMLCanvasElement); const canvas = (document.querySelector('#gameCanvas') as HTMLCanvasElement);
export class VrApp { export class VrApp {