From bde1216ab3488c1f9c993a384d9d10d12141a6ba Mon Sep 17 00:00:00 2001 From: kwaroran Date: Wed, 22 Nov 2023 18:51:12 +0900 Subject: [PATCH] [test] peer --- package.json | 3 +- pnpm-lock.yaml | 123 +++++++++++++- src/lang/en.ts | 3 +- src/lib/Setting/Pages/AdvancedSettings.svelte | 14 ++ src/lib/SideBars/SideChatList.svelte | 15 +- src/lib/SideBars/Sidebar.svelte | 20 +++ src/ts/storage/database.ts | 2 + src/ts/storage/globalApi.ts | 4 +- src/ts/sync/multiuser.ts | 153 ++++++++++++++++++ 9 files changed, 328 insertions(+), 9 deletions(-) create mode 100644 src/ts/sync/multiuser.ts diff --git a/package.json b/package.json index e8317a93..c55db78c 100644 --- a/package.json +++ b/package.json @@ -39,12 +39,13 @@ "libsodium-wrappers-sumo": "^0.7.11", "localforage": "^1.10.0", "lodash": "^4.17.21", - "lucide-svelte": "^0.260.0", + "lucide-svelte": "^0.292.0", "marked": "^5.1.1", "ml-distance": "^4.0.1", "mobile-drag-drop": "3.0.0-rc.0", "msgpackr": "^1.9.5", "node-html-parser": "^6.1.5", + "peerjs": "^1.5.1", "png-chunk-text": "^1.0.0", "png-chunks-encode": "^1.0.0", "png-chunks-extract": "^1.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8a0a93d4..105a71b8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -81,8 +81,8 @@ dependencies: specifier: ^4.17.21 version: 4.17.21 lucide-svelte: - specifier: ^0.260.0 - version: 0.260.0(svelte@4.1.0) + specifier: ^0.292.0 + version: 0.292.0(svelte@4.1.0) marked: specifier: ^5.1.1 version: 5.1.1 @@ -98,6 +98,9 @@ dependencies: node-html-parser: specifier: ^6.1.5 version: 6.1.5 + peerjs: + specifier: ^1.5.1 + version: 1.5.1 png-chunk-text: specifier: ^1.0.0 version: 1.0.0 @@ -292,6 +295,54 @@ packages: tslib: 2.6.0 dev: false + /@cbor-extract/cbor-extract-darwin-arm64@2.1.1: + resolution: {integrity: sha512-blVBy5MXz6m36Vx0DfLd7PChOQKEs8lK2bD1WJn/vVgG4FXZiZmZb2GECHFvVPA5T7OnODd9xZiL3nMCv6QUhA==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@cbor-extract/cbor-extract-darwin-x64@2.1.1: + resolution: {integrity: sha512-h6KFOzqk8jXTvkOftyRIWGrd7sKQzQv2jVdTL9nKSf3D2drCvQB/LHUxAOpPXo3pv2clDtKs3xnHalpEh3rDsw==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@cbor-extract/cbor-extract-linux-arm64@2.1.1: + resolution: {integrity: sha512-SxAaRcYf8S0QHaMc7gvRSiTSr7nUYMqbUdErBEu+HYA4Q6UNydx1VwFE68hGcp1qvxcy9yT5U7gA+a5XikfwSQ==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@cbor-extract/cbor-extract-linux-arm@2.1.1: + resolution: {integrity: sha512-ds0uikdcIGUjPyraV4oJqyVE5gl/qYBpa/Wnh6l6xLE2lj/hwnjT2XcZCChdXwW/YFZ1LUHs6waoYN8PmK0nKQ==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@cbor-extract/cbor-extract-linux-x64@2.1.1: + resolution: {integrity: sha512-GVK+8fNIE9lJQHAlhOROYiI0Yd4bAZ4u++C2ZjlkS3YmO6hi+FUxe6Dqm+OKWTcMpL/l71N6CQAmaRcb4zyJuA==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@cbor-extract/cbor-extract-win32-x64@2.1.1: + resolution: {integrity: sha512-2Niq1C41dCRIDeD8LddiH+mxGlO7HJ612Ll3D/E73ZWBmycued+8ghTr/Ho3CMOWPUEr08XtyBMVXAjqF+TcKw==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + /@dqbd/tiktoken@1.0.7: resolution: {integrity: sha512-bhR5k5W+8GLzysjk8zTMVygQZsgvf7W1F0IlL4ZQ5ugjo5rCyiwGM5d8DYriXspytfu98tv59niang3/T+FoDw==} dev: false @@ -526,6 +577,11 @@ packages: resolution: {integrity: sha512-whiQ+40ohtAFoFOGcje1Io7BMr434Wh3hM3nBCWlJMpXxL5Rlig/AH9wjyUPsytKwWTEe7RoYPyXSbFw5Vs6Tw==} dev: false + /@msgpack/msgpack@2.8.0: + resolution: {integrity: sha512-h9u4u/jiIRKbq25PM+zymTyW6bhTzELvOoUd+AvYriWOAKpLGnIamaET3pnHYoI5iYphAHBI4ayx0MehR+VVPQ==} + engines: {node: '>= 10'} + dev: false + /@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.2: resolution: {integrity: sha512-9bfjwDxIDWmmOKusUcqdS4Rw+SETlp9Dy39Xui9BEGEk19dDwH0jhipwFzEff/pFg95NKymc6TOTbRKcWeRqyQ==} cpu: [arm64] @@ -1358,6 +1414,28 @@ packages: resolution: {integrity: sha512-Vdhm5S11DaFVLlyiKu4hiUTkpZu+y1KA/rZZqVQfOD5YdDT/eQKlkt7NaE0WGOFgX32diqt9MiP9CAiFeRklaA==} dev: true + /cbor-extract@2.1.1: + resolution: {integrity: sha512-1UX977+L+zOJHsp0mWFG13GLwO6ucKgSmSW6JTl8B9GUvACvHeIVpFqhU92299Z6PfD09aTXDell5p+lp1rUFA==} + hasBin: true + requiresBuild: true + dependencies: + node-gyp-build-optional-packages: 5.0.3 + optionalDependencies: + '@cbor-extract/cbor-extract-darwin-arm64': 2.1.1 + '@cbor-extract/cbor-extract-darwin-x64': 2.1.1 + '@cbor-extract/cbor-extract-linux-arm': 2.1.1 + '@cbor-extract/cbor-extract-linux-arm64': 2.1.1 + '@cbor-extract/cbor-extract-linux-x64': 2.1.1 + '@cbor-extract/cbor-extract-win32-x64': 2.1.1 + dev: false + optional: true + + /cbor-x@1.5.6: + resolution: {integrity: sha512-+TXdnDNdr8JH5GQRoAhjdT/5s5N+b71s2Nz8DpDRyuWx0uzMj8JTR3AqqMTBO/1HtUBHZpmK1enD2ViXFx0Nug==} + optionalDependencies: + cbor-extract: 2.1.1 + dev: false + /chokidar@3.5.3: resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} engines: {node: '>= 8.10.0'} @@ -1727,6 +1805,10 @@ packages: engines: {node: '>= 0.6'} dev: false + /eventemitter3@4.0.7: + resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + dev: false + /execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} @@ -2286,8 +2368,8 @@ packages: yallist: 4.0.0 dev: false - /lucide-svelte@0.260.0(svelte@4.1.0): - resolution: {integrity: sha512-fvR/42lZdIaW9RCVIouIMO9LgxwBcE4M770Hpl1ITL2At5YamgQ8J/652mTBXnX7qfiTCND/mSVnnXGESypaEw==} + /lucide-svelte@0.292.0(svelte@4.1.0): + resolution: {integrity: sha512-bnTpg9pbm6pQDc+YiLK2yxtRFk2Cc+hbzwjAPaV85k56x10CJ9LsXjon6wRrlNTSdxJR7GOsRjz0A5ZNu3Z7dg==} peerDependencies: svelte: '>=3 <5' dependencies: @@ -2511,6 +2593,12 @@ packages: resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==} dev: false + /node-gyp-build-optional-packages@5.0.3: + resolution: {integrity: sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA==} + hasBin: true + dev: false + optional: true + /node-gyp-build-optional-packages@5.0.7: resolution: {integrity: sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w==} hasBin: true @@ -2678,6 +2766,22 @@ packages: resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} dev: false + /peerjs-js-binarypack@2.0.0: + resolution: {integrity: sha512-wu+L0Qeg4IH2DXm3B6xKP5ODeCIovwEEO/Fu3MVqApPQeVLzSdZpFzQzPobh+sdhUWMQGEO7YxHeiwpPngLjqQ==} + engines: {node: '>= 14.0.0'} + dev: false + + /peerjs@1.5.1: + resolution: {integrity: sha512-jpE2jPZ99vuSVHBAhn7bVCPKlwsPgcAqgcDKEZR4L7SaMaEL6wqD/G6VI0+awmhuEFcUN2ttusly+sKQGD64hQ==} + engines: {node: '>= 14'} + dependencies: + '@msgpack/msgpack': 2.8.0 + cbor-x: 1.5.6 + eventemitter3: 4.0.7 + peerjs-js-binarypack: 2.0.0 + webrtc-adapter: 8.2.3 + dev: false + /periscopic@3.1.0: resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==} dependencies: @@ -3025,6 +3129,10 @@ packages: xmlchars: 2.2.0 dev: false + /sdp@3.2.0: + resolution: {integrity: sha512-d7wDPgDV3DDiqulJjKiV2865wKsJ34YI+NDREbm+FySq6WuKOikwyNQcm+doLAZ1O6ltdO0SeKle2xMpN3Brgw==} + dev: false + /semver@7.5.4: resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} engines: {node: '>=10'} @@ -3608,6 +3716,13 @@ packages: engines: {node: '>=12'} dev: false + /webrtc-adapter@8.2.3: + resolution: {integrity: sha512-gnmRz++suzmvxtp3ehQts6s2JtAGPuDPjA1F3a9ckNpG1kYdYuHWYpazoAnL9FS5/B21tKlhkorbdCXat0+4xQ==} + engines: {node: '>=6.0.0', npm: '>=3.10.0'} + dependencies: + sdp: 3.2.0 + dev: false + /whatwg-encoding@2.0.0: resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==} engines: {node: '>=12'} diff --git a/src/lang/en.ts b/src/lang/en.ts index 2cf611ef..e0471db8 100644 --- a/src/lang/en.ts +++ b/src/lang/en.ts @@ -449,5 +449,6 @@ export const languageEnglish = { largePortrait: "Portrait", postImage: "Post Image", lorePlus: "LoreBook+", - reverseProxyOobaMode: "Reverse Proxy Ooba Mode" + reverseProxyOobaMode: "Reverse Proxy Ooba Mode", + joinMultiUserRoom: "Join MultiUser Room", } \ No newline at end of file diff --git a/src/lib/Setting/Pages/AdvancedSettings.svelte b/src/lib/Setting/Pages/AdvancedSettings.svelte index d24bbb3c..3d8f90e2 100644 --- a/src/lib/Setting/Pages/AdvancedSettings.svelte +++ b/src/lib/Setting/Pages/AdvancedSettings.svelte @@ -78,6 +78,20 @@ +
+ { + // access code is "tendo" + // I just put it on source code so it's not really a secret + // well, if you are reading this, you are a developer, so you can use this feature + + const accessCode = 'tendo' + if(prompt("Access Code") === accessCode){ + $DataBase.tpo = !$DataBase.tpo + } + }}> + + +
+ {/if} + {:else if sideBarMode === 2} + {/if} diff --git a/src/ts/storage/database.ts b/src/ts/storage/database.ts index d55d04e1..9b9a7a02 100644 --- a/src/ts/storage/database.ts +++ b/src/ts/storage/database.ts @@ -505,6 +505,7 @@ export interface Database{ gptVisionQuality:string reverseProxyOobaMode:boolean reverseProxyOobaArgs: OobaChatCompletionRequestParams + tpo?:boolean } export interface customscript{ @@ -601,6 +602,7 @@ export interface character{ extentions?:{[key:string]:any} largePortrait?:boolean lorePlus?:boolean + } diff --git a/src/ts/storage/globalApi.ts b/src/ts/storage/globalApi.ts index bb36d45e..5ddae585 100644 --- a/src/ts/storage/globalApi.ts +++ b/src/ts/storage/globalApi.ts @@ -922,7 +922,9 @@ export function checkCharOrder() { const charId = db.characters[i].chaId charIdList.push(charId) if(!ordered.includes(charId)){ - db.characterOrder.push(charId) + if(charId !== '§temp'){ + db.characterOrder.push(charId) + } } } diff --git a/src/ts/sync/multiuser.ts b/src/ts/sync/multiuser.ts new file mode 100644 index 00000000..a5c8e109 --- /dev/null +++ b/src/ts/sync/multiuser.ts @@ -0,0 +1,153 @@ +import { v4 } from 'uuid'; +import { alertError, alertInput, alertNormal, alertWait } from '../alert'; +import { get } from 'svelte/store'; +import { DataBase, setDatabase, type character } from '../storage/database'; +import { selectedCharID } from '../stores'; +import { cloneDeep } from 'lodash'; +import { findCharacterIndexbyId, sleep } from '../util'; +import type { DataConnection, Peer } from 'peerjs'; + +async function importPeerJS(){ + return await import('peerjs'); +} + +let conn:DataConnection +let peer:Peer +let connections:DataConnection[] = [] + +export async function createMultiuserRoom(){ + //create a room with webrtc + alertWait("Loading...") + + const peerJS = await importPeerJS(); + const roomId = v4(); + peer = new peerJS.Peer( + roomId + "-risuai-multiuser" + ) + + peer.on('connection', function(conn) { + connections.push(conn) + conn.on('data', function(data:ReciveData) { + if(data.type === 'request-char'){ + const db = get(DataBase) + const selectedCharId = get(selectedCharID) + const char = cloneDeep(db.characters[selectedCharId]) + if(char.type === 'group'){ + return + } + char.chats = [char.chats[char.chatPage]] + conn.send({ + type: 'receive-char', + data: char + }); + } + if(data.type === 'receive-char'){ + const db = get(DataBase) + const selectedCharId = get(selectedCharID) + const char = cloneDeep(db.characters[selectedCharId]) + const recivedChar = data.data + if(char.type === 'group'){ + return + } + char.chats[char.chatPage] = recivedChar.chats[0] + sendPeerChar() + } + }); + }); + + + alertNormal("Room ID: " + roomId) + return +} + +interface ReciveFirst{ + type: 'receive-char', + data: character +} +interface RequestFirst{ + type: 'request-char' +} + +type ReciveData = ReciveFirst|RequestFirst + +export async function joinMultiuserRoom(){ + + const roomId = await alertInput("Enter room id") + //join a room with webrtc + alertWait("Loading...") + const peerJS = await importPeerJS(); + peer = new peerJS.Peer( + v4() + "-risuai-multiuser-join" + ) + + conn = peer.connect(roomId + '-risuai-multiuser'); + + alertWait("Waiting for host to accept connection") + + let open = false + conn.on('open', function() { + open = true + conn.send({ + type: 'request-char', + }); + conn.on('data', function(data:ReciveData) { + switch(data.type){ + case 'receive-char':{ + //create temp character + const db = get(DataBase) + const cha = data.data + cha.chaId = '§temp' + cha.chatPage = 0 + const ind = findCharacterIndexbyId('§temp') + const selectedcharIndex = get(selectedCharID) + if(ind === -1){ + db.characters.push(cha) + } + else{ + db.characters[ind] = cha + } + const tempInd = findCharacterIndexbyId('§temp') + if(selectedcharIndex !== tempInd){ + selectedCharID.set(tempInd) + } + setDatabase(db) + break + } + } + }); + }); + + let waitTime = 0 + while(!open){ + await sleep(100) + waitTime += 100 + if(waitTime > 10000){ + alertError("Connection timed out") + return + } + } + + return { + peer, roomId, conn + } + +} + + +export function sendPeerChar(){ + if(!conn){ + // host user + for(const connection of connections){ + connection.send({ + type: 'receive-char', + data: get(DataBase).characters[get(selectedCharID)] + }); + } + } + else{ + conn.send({ + type: 'receive-char', + data: get(DataBase).characters[get(selectedCharID)] + }); + } +} \ No newline at end of file