Procházet zdrojové kódy

fix: 增加长连接

ansoni před 3 týdny
rodič
revize
62ad0f88f1

+ 0 - 1
package.json

@@ -44,7 +44,6 @@
     "sass": "^1.77.8",
     "swiper": "^11.1.5",
     "tailwind-merge": "^2.4.0",
-    "twebp2": "0.0.1-beta.8",
     "zustand": "^4.5.4"
   },
   "devDependencies": {

+ 35 - 323
pnpm-lock.yaml

@@ -71,9 +71,6 @@ importers:
       tailwind-merge:
         specifier: ^2.4.0
         version: 2.6.0
-      twebp2:
-        specifier: 0.0.1-beta.8
-        version: 0.0.1-beta.8
       zustand:
         specifier: ^4.5.4
         version: 4.5.5(@types/react@18.3.18)(immer@10.1.1)(react@18.3.1)
@@ -144,9 +141,6 @@ packages:
     resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==, tarball: https://registry.npmmirror.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz}
     engines: {node: '>=10.0.0'}
 
-  '@emnapi/runtime@1.4.3':
-    resolution: {integrity: sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==}
-
   '@eslint-community/eslint-utils@4.4.1':
     resolution: {integrity: sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -421,122 +415,6 @@ packages:
     resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==}
     deprecated: Use @eslint/object-schema instead
 
-  '@img/sharp-darwin-arm64@0.34.2':
-    resolution: {integrity: sha512-OfXHZPppddivUJnqyKoi5YVeHRkkNE2zUFT2gbpKxp/JZCFYEYubnMg+gOp6lWfasPrTS+KPosKqdI+ELYVDtg==}
-    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
-    cpu: [arm64]
-    os: [darwin]
-
-  '@img/sharp-darwin-x64@0.34.2':
-    resolution: {integrity: sha512-dYvWqmjU9VxqXmjEtjmvHnGqF8GrVjM2Epj9rJ6BUIXvk8slvNDJbhGFvIoXzkDhrJC2jUxNLz/GUjjvSzfw+g==}
-    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
-    cpu: [x64]
-    os: [darwin]
-
-  '@img/sharp-libvips-darwin-arm64@1.1.0':
-    resolution: {integrity: sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA==}
-    cpu: [arm64]
-    os: [darwin]
-
-  '@img/sharp-libvips-darwin-x64@1.1.0':
-    resolution: {integrity: sha512-Xzc2ToEmHN+hfvsl9wja0RlnXEgpKNmftriQp6XzY/RaSfwD9th+MSh0WQKzUreLKKINb3afirxW7A0fz2YWuQ==}
-    cpu: [x64]
-    os: [darwin]
-
-  '@img/sharp-libvips-linux-arm64@1.1.0':
-    resolution: {integrity: sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew==}
-    cpu: [arm64]
-    os: [linux]
-
-  '@img/sharp-libvips-linux-arm@1.1.0':
-    resolution: {integrity: sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA==}
-    cpu: [arm]
-    os: [linux]
-
-  '@img/sharp-libvips-linux-ppc64@1.1.0':
-    resolution: {integrity: sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ==}
-    cpu: [ppc64]
-    os: [linux]
-
-  '@img/sharp-libvips-linux-s390x@1.1.0':
-    resolution: {integrity: sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA==}
-    cpu: [s390x]
-    os: [linux]
-
-  '@img/sharp-libvips-linux-x64@1.1.0':
-    resolution: {integrity: sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q==}
-    cpu: [x64]
-    os: [linux]
-
-  '@img/sharp-libvips-linuxmusl-arm64@1.1.0':
-    resolution: {integrity: sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w==}
-    cpu: [arm64]
-    os: [linux]
-
-  '@img/sharp-libvips-linuxmusl-x64@1.1.0':
-    resolution: {integrity: sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A==}
-    cpu: [x64]
-    os: [linux]
-
-  '@img/sharp-linux-arm64@0.34.2':
-    resolution: {integrity: sha512-D8n8wgWmPDakc83LORcfJepdOSN6MvWNzzz2ux0MnIbOqdieRZwVYY32zxVx+IFUT8er5KPcyU3XXsn+GzG/0Q==}
-    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
-    cpu: [arm64]
-    os: [linux]
-
-  '@img/sharp-linux-arm@0.34.2':
-    resolution: {integrity: sha512-0DZzkvuEOqQUP9mo2kjjKNok5AmnOr1jB2XYjkaoNRwpAYMDzRmAqUIa1nRi58S2WswqSfPOWLNOr0FDT3H5RQ==}
-    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
-    cpu: [arm]
-    os: [linux]
-
-  '@img/sharp-linux-s390x@0.34.2':
-    resolution: {integrity: sha512-EGZ1xwhBI7dNISwxjChqBGELCWMGDvmxZXKjQRuqMrakhO8QoMgqCrdjnAqJq/CScxfRn+Bb7suXBElKQpPDiw==}
-    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
-    cpu: [s390x]
-    os: [linux]
-
-  '@img/sharp-linux-x64@0.34.2':
-    resolution: {integrity: sha512-sD7J+h5nFLMMmOXYH4DD9UtSNBD05tWSSdWAcEyzqW8Cn5UxXvsHAxmxSesYUsTOBmUnjtxghKDl15EvfqLFbQ==}
-    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
-    cpu: [x64]
-    os: [linux]
-
-  '@img/sharp-linuxmusl-arm64@0.34.2':
-    resolution: {integrity: sha512-NEE2vQ6wcxYav1/A22OOxoSOGiKnNmDzCYFOZ949xFmrWZOVII1Bp3NqVVpvj+3UeHMFyN5eP/V5hzViQ5CZNA==}
-    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
-    cpu: [arm64]
-    os: [linux]
-
-  '@img/sharp-linuxmusl-x64@0.34.2':
-    resolution: {integrity: sha512-DOYMrDm5E6/8bm/yQLCWyuDJwUnlevR8xtF8bs+gjZ7cyUNYXiSf/E8Kp0Ss5xasIaXSHzb888V1BE4i1hFhAA==}
-    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
-    cpu: [x64]
-    os: [linux]
-
-  '@img/sharp-wasm32@0.34.2':
-    resolution: {integrity: sha512-/VI4mdlJ9zkaq53MbIG6rZY+QRN3MLbR6usYlgITEzi4Rpx5S6LFKsycOQjkOGmqTNmkIdLjEvooFKwww6OpdQ==}
-    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
-    cpu: [wasm32]
-
-  '@img/sharp-win32-arm64@0.34.2':
-    resolution: {integrity: sha512-cfP/r9FdS63VA5k0xiqaNaEoGxBg9k7uE+RQGzuK9fHt7jib4zAVVseR9LsE4gJcNWgT6APKMNnCcnyOtmSEUQ==}
-    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
-    cpu: [arm64]
-    os: [win32]
-
-  '@img/sharp-win32-ia32@0.34.2':
-    resolution: {integrity: sha512-QLjGGvAbj0X/FXl8n1WbtQ6iVBpWU7JO94u/P2M4a8CFYsvQi4GW2mRy/JqkRx0qpBzaOdKJKw8uc930EX2AHw==}
-    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
-    cpu: [ia32]
-    os: [win32]
-
-  '@img/sharp-win32-x64@0.34.2':
-    resolution: {integrity: sha512-aUdT6zEYtDKCaxkofmmJDJYGCf0+pJg3eU9/oBuqvEeoB9dKI6ZLc/1iLJCTuJQDO4ptntAlkUmHgGjyuobZbw==}
-    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
-    cpu: [x64]
-    os: [win32]
-
   '@isaacs/cliui@8.0.2':
     resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
     engines: {node: '>=12'}
@@ -572,55 +450,59 @@ packages:
     resolution: {integrity: sha512-svSFxW9f3xDaZA3idQmlFw7SusOuWTpDTAeBlO3AEPDltrraV+lqs7mAc6A27YdnpQVVIA3sODqUAAHdWhVWsA==}
 
   '@next/swc-darwin-arm64@14.2.4':
-    resolution: {integrity: sha512-AH3mO4JlFUqsYcwFUHb1wAKlebHU/Hv2u2kb1pAuRanDZ7pD/A/KPD98RHZmwsJpdHQwfEc/06mgpSzwrJYnNg==}
+    resolution: {integrity: sha512-AH3mO4JlFUqsYcwFUHb1wAKlebHU/Hv2u2kb1pAuRanDZ7pD/A/KPD98RHZmwsJpdHQwfEc/06mgpSzwrJYnNg==, tarball: https://registry.npmmirror.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.4.tgz}
     engines: {node: '>= 10'}
     cpu: [arm64]
     os: [darwin]
 
   '@next/swc-darwin-x64@14.2.4':
-    resolution: {integrity: sha512-QVadW73sWIO6E2VroyUjuAxhWLZWEpiFqHdZdoQ/AMpN9YWGuHV8t2rChr0ahy+irKX5mlDU7OY68k3n4tAZTg==}
+    resolution: {integrity: sha512-QVadW73sWIO6E2VroyUjuAxhWLZWEpiFqHdZdoQ/AMpN9YWGuHV8t2rChr0ahy+irKX5mlDU7OY68k3n4tAZTg==, tarball: https://registry.npmmirror.com/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.4.tgz}
     engines: {node: '>= 10'}
     cpu: [x64]
     os: [darwin]
 
   '@next/swc-linux-arm64-gnu@14.2.4':
-    resolution: {integrity: sha512-KT6GUrb3oyCfcfJ+WliXuJnD6pCpZiosx2X3k66HLR+DMoilRb76LpWPGb4tZprawTtcnyrv75ElD6VncVamUQ==}
+    resolution: {integrity: sha512-KT6GUrb3oyCfcfJ+WliXuJnD6pCpZiosx2X3k66HLR+DMoilRb76LpWPGb4tZprawTtcnyrv75ElD6VncVamUQ==, tarball: https://registry.npmmirror.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.4.tgz}
     engines: {node: '>= 10'}
     cpu: [arm64]
     os: [linux]
+    libc: [glibc]
 
   '@next/swc-linux-arm64-musl@14.2.4':
-    resolution: {integrity: sha512-Alv8/XGSs/ytwQcbCHwze1HmiIkIVhDHYLjczSVrf0Wi2MvKn/blt7+S6FJitj3yTlMwMxII1gIJ9WepI4aZ/A==}
+    resolution: {integrity: sha512-Alv8/XGSs/ytwQcbCHwze1HmiIkIVhDHYLjczSVrf0Wi2MvKn/blt7+S6FJitj3yTlMwMxII1gIJ9WepI4aZ/A==, tarball: https://registry.npmmirror.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.4.tgz}
     engines: {node: '>= 10'}
     cpu: [arm64]
     os: [linux]
+    libc: [musl]
 
   '@next/swc-linux-x64-gnu@14.2.4':
-    resolution: {integrity: sha512-ze0ShQDBPCqxLImzw4sCdfnB3lRmN3qGMB2GWDRlq5Wqy4G36pxtNOo2usu/Nm9+V2Rh/QQnrRc2l94kYFXO6Q==}
+    resolution: {integrity: sha512-ze0ShQDBPCqxLImzw4sCdfnB3lRmN3qGMB2GWDRlq5Wqy4G36pxtNOo2usu/Nm9+V2Rh/QQnrRc2l94kYFXO6Q==, tarball: https://registry.npmmirror.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.4.tgz}
     engines: {node: '>= 10'}
     cpu: [x64]
     os: [linux]
+    libc: [glibc]
 
   '@next/swc-linux-x64-musl@14.2.4':
-    resolution: {integrity: sha512-8dwC0UJoc6fC7PX70csdaznVMNr16hQrTDAMPvLPloazlcaWfdPogq+UpZX6Drqb1OBlwowz8iG7WR0Tzk/diQ==}
+    resolution: {integrity: sha512-8dwC0UJoc6fC7PX70csdaznVMNr16hQrTDAMPvLPloazlcaWfdPogq+UpZX6Drqb1OBlwowz8iG7WR0Tzk/diQ==, tarball: https://registry.npmmirror.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.4.tgz}
     engines: {node: '>= 10'}
     cpu: [x64]
     os: [linux]
+    libc: [musl]
 
   '@next/swc-win32-arm64-msvc@14.2.4':
-    resolution: {integrity: sha512-jxyg67NbEWkDyvM+O8UDbPAyYRZqGLQDTPwvrBBeOSyVWW/jFQkQKQ70JDqDSYg1ZDdl+E3nkbFbq8xM8E9x8A==}
+    resolution: {integrity: sha512-jxyg67NbEWkDyvM+O8UDbPAyYRZqGLQDTPwvrBBeOSyVWW/jFQkQKQ70JDqDSYg1ZDdl+E3nkbFbq8xM8E9x8A==, tarball: https://registry.npmmirror.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.4.tgz}
     engines: {node: '>= 10'}
     cpu: [arm64]
     os: [win32]
 
   '@next/swc-win32-ia32-msvc@14.2.4':
-    resolution: {integrity: sha512-twrmN753hjXRdcrZmZttb/m5xaCBFa48Dt3FbeEItpJArxriYDunWxJn+QFXdJ3hPkm4u7CKxncVvnmgQMY1ag==}
+    resolution: {integrity: sha512-twrmN753hjXRdcrZmZttb/m5xaCBFa48Dt3FbeEItpJArxriYDunWxJn+QFXdJ3hPkm4u7CKxncVvnmgQMY1ag==, tarball: https://registry.npmmirror.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.4.tgz}
     engines: {node: '>= 10'}
     cpu: [ia32]
     os: [win32]
 
   '@next/swc-win32-x64-msvc@14.2.4':
-    resolution: {integrity: sha512-tkLrjBzqFTP8DVrAAQmZelEahfR9OxWpFR++vAI9FBhCiIxtwHwBHC23SBHCTURBtwB4kc/x44imVOnkKGNVGg==}
+    resolution: {integrity: sha512-tkLrjBzqFTP8DVrAAQmZelEahfR9OxWpFR++vAI9FBhCiIxtwHwBHC23SBHCTURBtwB4kc/x44imVOnkKGNVGg==, tarball: https://registry.npmmirror.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.4.tgz}
     engines: {node: '>= 10'}
     cpu: [x64]
     os: [win32]
@@ -648,89 +530,95 @@ packages:
       react-dom: ^18 || ^19
 
   '@parcel/watcher-android-arm64@2.5.0':
-    resolution: {integrity: sha512-qlX4eS28bUcQCdribHkg/herLe+0A9RyYC+mm2PXpncit8z5b3nSqGVzMNR3CmtAOgRutiZ02eIJJgP/b1iEFQ==}
+    resolution: {integrity: sha512-qlX4eS28bUcQCdribHkg/herLe+0A9RyYC+mm2PXpncit8z5b3nSqGVzMNR3CmtAOgRutiZ02eIJJgP/b1iEFQ==, tarball: https://registry.npmmirror.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.0.tgz}
     engines: {node: '>= 10.0.0'}
     cpu: [arm64]
     os: [android]
 
   '@parcel/watcher-darwin-arm64@2.5.0':
-    resolution: {integrity: sha512-hyZ3TANnzGfLpRA2s/4U1kbw2ZI4qGxaRJbBH2DCSREFfubMswheh8TeiC1sGZ3z2jUf3s37P0BBlrD3sjVTUw==}
+    resolution: {integrity: sha512-hyZ3TANnzGfLpRA2s/4U1kbw2ZI4qGxaRJbBH2DCSREFfubMswheh8TeiC1sGZ3z2jUf3s37P0BBlrD3sjVTUw==, tarball: https://registry.npmmirror.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.0.tgz}
     engines: {node: '>= 10.0.0'}
     cpu: [arm64]
     os: [darwin]
 
   '@parcel/watcher-darwin-x64@2.5.0':
-    resolution: {integrity: sha512-9rhlwd78saKf18fT869/poydQK8YqlU26TMiNg7AIu7eBp9adqbJZqmdFOsbZ5cnLp5XvRo9wcFmNHgHdWaGYA==}
+    resolution: {integrity: sha512-9rhlwd78saKf18fT869/poydQK8YqlU26TMiNg7AIu7eBp9adqbJZqmdFOsbZ5cnLp5XvRo9wcFmNHgHdWaGYA==, tarball: https://registry.npmmirror.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.0.tgz}
     engines: {node: '>= 10.0.0'}
     cpu: [x64]
     os: [darwin]
 
   '@parcel/watcher-freebsd-x64@2.5.0':
-    resolution: {integrity: sha512-syvfhZzyM8kErg3VF0xpV8dixJ+RzbUaaGaeb7uDuz0D3FK97/mZ5AJQ3XNnDsXX7KkFNtyQyFrXZzQIcN49Tw==}
+    resolution: {integrity: sha512-syvfhZzyM8kErg3VF0xpV8dixJ+RzbUaaGaeb7uDuz0D3FK97/mZ5AJQ3XNnDsXX7KkFNtyQyFrXZzQIcN49Tw==, tarball: https://registry.npmmirror.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.0.tgz}
     engines: {node: '>= 10.0.0'}
     cpu: [x64]
     os: [freebsd]
 
   '@parcel/watcher-linux-arm-glibc@2.5.0':
-    resolution: {integrity: sha512-0VQY1K35DQET3dVYWpOaPFecqOT9dbuCfzjxoQyif1Wc574t3kOSkKevULddcR9znz1TcklCE7Ht6NIxjvTqLA==}
+    resolution: {integrity: sha512-0VQY1K35DQET3dVYWpOaPFecqOT9dbuCfzjxoQyif1Wc574t3kOSkKevULddcR9znz1TcklCE7Ht6NIxjvTqLA==, tarball: https://registry.npmmirror.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.0.tgz}
     engines: {node: '>= 10.0.0'}
     cpu: [arm]
     os: [linux]
+    libc: [glibc]
 
   '@parcel/watcher-linux-arm-musl@2.5.0':
-    resolution: {integrity: sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==}
+    resolution: {integrity: sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==, tarball: https://registry.npmmirror.com/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.0.tgz}
     engines: {node: '>= 10.0.0'}
     cpu: [arm]
     os: [linux]
+    libc: [musl]
 
   '@parcel/watcher-linux-arm64-glibc@2.5.0':
-    resolution: {integrity: sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==}
+    resolution: {integrity: sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==, tarball: https://registry.npmmirror.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.0.tgz}
     engines: {node: '>= 10.0.0'}
     cpu: [arm64]
     os: [linux]
+    libc: [glibc]
 
   '@parcel/watcher-linux-arm64-musl@2.5.0':
-    resolution: {integrity: sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==}
+    resolution: {integrity: sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==, tarball: https://registry.npmmirror.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.0.tgz}
     engines: {node: '>= 10.0.0'}
     cpu: [arm64]
     os: [linux]
+    libc: [musl]
 
   '@parcel/watcher-linux-x64-glibc@2.5.0':
-    resolution: {integrity: sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==}
+    resolution: {integrity: sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==, tarball: https://registry.npmmirror.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.0.tgz}
     engines: {node: '>= 10.0.0'}
     cpu: [x64]
     os: [linux]
+    libc: [glibc]
 
   '@parcel/watcher-linux-x64-musl@2.5.0':
-    resolution: {integrity: sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==}
+    resolution: {integrity: sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==, tarball: https://registry.npmmirror.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.0.tgz}
     engines: {node: '>= 10.0.0'}
     cpu: [x64]
     os: [linux]
+    libc: [musl]
 
   '@parcel/watcher-win32-arm64@2.5.0':
-    resolution: {integrity: sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==}
+    resolution: {integrity: sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==, tarball: https://registry.npmmirror.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.0.tgz}
     engines: {node: '>= 10.0.0'}
     cpu: [arm64]
     os: [win32]
 
   '@parcel/watcher-win32-ia32@2.5.0':
-    resolution: {integrity: sha512-+rgpsNRKwo8A53elqbbHXdOMtY/tAtTzManTWShB5Kk54N8Q9mzNWV7tV+IbGueCbcj826MfWGU3mprWtuf1TA==}
+    resolution: {integrity: sha512-+rgpsNRKwo8A53elqbbHXdOMtY/tAtTzManTWShB5Kk54N8Q9mzNWV7tV+IbGueCbcj826MfWGU3mprWtuf1TA==, tarball: https://registry.npmmirror.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.0.tgz}
     engines: {node: '>= 10.0.0'}
     cpu: [ia32]
     os: [win32]
 
   '@parcel/watcher-win32-x64@2.5.0':
-    resolution: {integrity: sha512-lPrxve92zEHdgeff3aiu4gDOIt4u7sJYha6wbdEZDCDUhtjTsOMiaJzG5lMY4GkWH8p0fMmO2Ppq5G5XXG+DQw==}
+    resolution: {integrity: sha512-lPrxve92zEHdgeff3aiu4gDOIt4u7sJYha6wbdEZDCDUhtjTsOMiaJzG5lMY4GkWH8p0fMmO2Ppq5G5XXG+DQw==, tarball: https://registry.npmmirror.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.0.tgz}
     engines: {node: '>= 10.0.0'}
     cpu: [x64]
     os: [win32]
 
   '@parcel/watcher@2.5.0':
-    resolution: {integrity: sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ==}
+    resolution: {integrity: sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ==, tarball: https://registry.npmmirror.com/@parcel/watcher/-/watcher-2.5.0.tgz}
     engines: {node: '>= 10.0.0'}
 
   '@pkgjs/parseargs@0.11.0':
-    resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
+    resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==, tarball: https://registry.npmmirror.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz}
     engines: {node: '>=14'}
 
   '@polka/url@1.0.0-next.29':
@@ -1082,17 +970,6 @@ packages:
   color-name@1.1.4:
     resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
 
-  color-string@1.9.1:
-    resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==}
-
-  color@4.2.3:
-    resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==}
-    engines: {node: '>=12.5.0'}
-
-  colors@1.4.0:
-    resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==}
-    engines: {node: '>=0.1.90'}
-
   combined-stream@1.0.8:
     resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
     engines: {node: '>= 0.8'}
@@ -1185,10 +1062,6 @@ packages:
     engines: {node: '>=0.10'}
     hasBin: true
 
-  detect-libc@2.0.4:
-    resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==}
-    engines: {node: '>=8'}
-
   didyoumean@1.2.2:
     resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
 
@@ -1472,7 +1345,7 @@ packages:
     resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
 
   fsevents@2.3.3:
-    resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+    resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==, tarball: https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz}
     engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
     os: [darwin]
 
@@ -1623,9 +1496,6 @@ packages:
     resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==}
     engines: {node: '>= 0.4'}
 
-  is-arrayish@0.3.2:
-    resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
-
   is-async-function@2.0.0:
     resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==}
     engines: {node: '>= 0.4'}
@@ -2330,11 +2200,6 @@ packages:
     engines: {node: '>=10'}
     hasBin: true
 
-  semver@7.7.2:
-    resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==}
-    engines: {node: '>=10'}
-    hasBin: true
-
   set-function-length@1.2.2:
     resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
     engines: {node: '>= 0.4'}
@@ -2343,10 +2208,6 @@ packages:
     resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==}
     engines: {node: '>= 0.4'}
 
-  sharp@0.34.2:
-    resolution: {integrity: sha512-lszvBmB9QURERtyKT2bNmsgxXK0ShJrL/fvqlonCo7e6xBF8nT8xU6pW+PMIbLsz0RxQk3rgH9kd8UmvOzlMJg==}
-    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
-
   shebang-command@2.0.0:
     resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
     engines: {node: '>=8'}
@@ -2375,9 +2236,6 @@ packages:
     resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
     engines: {node: '>=14'}
 
-  simple-swizzle@0.2.2:
-    resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
-
   sirv@2.0.4:
     resolution: {integrity: sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==, tarball: https://registry.npmmirror.com/sirv/-/sirv-2.0.4.tgz}
     engines: {node: '>= 10'}
@@ -2524,10 +2382,6 @@ packages:
   tslib@2.8.1:
     resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
 
-  twebp2@0.0.1-beta.8:
-    resolution: {integrity: sha512-M9RxF6ClJf4kTnDpGoqSwaE+yWKcIp2oUUJhd2Ga6nW/AQ9rgre0OEq1sRKFBK3V85x76Cn3yY5xxVFCQ9nRxA==}
-    hasBin: true
-
   type-check@0.4.0:
     resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
     engines: {node: '>= 0.8.0'}
@@ -2692,11 +2546,6 @@ snapshots:
 
   '@discoveryjs/json-ext@0.5.7': {}
 
-  '@emnapi/runtime@1.4.3':
-    dependencies:
-      tslib: 2.8.1
-    optional: true
-
   '@eslint-community/eslint-utils@4.4.1(eslint@8.57.1)':
     dependencies:
       eslint: 8.57.1
@@ -3098,87 +2947,6 @@ snapshots:
 
   '@humanwhocodes/object-schema@2.0.3': {}
 
-  '@img/sharp-darwin-arm64@0.34.2':
-    optionalDependencies:
-      '@img/sharp-libvips-darwin-arm64': 1.1.0
-    optional: true
-
-  '@img/sharp-darwin-x64@0.34.2':
-    optionalDependencies:
-      '@img/sharp-libvips-darwin-x64': 1.1.0
-    optional: true
-
-  '@img/sharp-libvips-darwin-arm64@1.1.0':
-    optional: true
-
-  '@img/sharp-libvips-darwin-x64@1.1.0':
-    optional: true
-
-  '@img/sharp-libvips-linux-arm64@1.1.0':
-    optional: true
-
-  '@img/sharp-libvips-linux-arm@1.1.0':
-    optional: true
-
-  '@img/sharp-libvips-linux-ppc64@1.1.0':
-    optional: true
-
-  '@img/sharp-libvips-linux-s390x@1.1.0':
-    optional: true
-
-  '@img/sharp-libvips-linux-x64@1.1.0':
-    optional: true
-
-  '@img/sharp-libvips-linuxmusl-arm64@1.1.0':
-    optional: true
-
-  '@img/sharp-libvips-linuxmusl-x64@1.1.0':
-    optional: true
-
-  '@img/sharp-linux-arm64@0.34.2':
-    optionalDependencies:
-      '@img/sharp-libvips-linux-arm64': 1.1.0
-    optional: true
-
-  '@img/sharp-linux-arm@0.34.2':
-    optionalDependencies:
-      '@img/sharp-libvips-linux-arm': 1.1.0
-    optional: true
-
-  '@img/sharp-linux-s390x@0.34.2':
-    optionalDependencies:
-      '@img/sharp-libvips-linux-s390x': 1.1.0
-    optional: true
-
-  '@img/sharp-linux-x64@0.34.2':
-    optionalDependencies:
-      '@img/sharp-libvips-linux-x64': 1.1.0
-    optional: true
-
-  '@img/sharp-linuxmusl-arm64@0.34.2':
-    optionalDependencies:
-      '@img/sharp-libvips-linuxmusl-arm64': 1.1.0
-    optional: true
-
-  '@img/sharp-linuxmusl-x64@0.34.2':
-    optionalDependencies:
-      '@img/sharp-libvips-linuxmusl-x64': 1.1.0
-    optional: true
-
-  '@img/sharp-wasm32@0.34.2':
-    dependencies:
-      '@emnapi/runtime': 1.4.3
-    optional: true
-
-  '@img/sharp-win32-arm64@0.34.2':
-    optional: true
-
-  '@img/sharp-win32-ia32@0.34.2':
-    optional: true
-
-  '@img/sharp-win32-x64@0.34.2':
-    optional: true
-
   '@isaacs/cliui@8.0.2':
     dependencies:
       string-width: 5.1.2
@@ -3732,18 +3500,6 @@ snapshots:
 
   color-name@1.1.4: {}
 
-  color-string@1.9.1:
-    dependencies:
-      color-name: 1.1.4
-      simple-swizzle: 0.2.2
-
-  color@4.2.3:
-    dependencies:
-      color-convert: 2.0.1
-      color-string: 1.9.1
-
-  colors@1.4.0: {}
-
   combined-stream@1.0.8:
     dependencies:
       delayed-stream: 1.0.0
@@ -3819,8 +3575,6 @@ snapshots:
   detect-libc@1.0.3:
     optional: true
 
-  detect-libc@2.0.4: {}
-
   didyoumean@1.2.2: {}
 
   dir-glob@3.0.1:
@@ -4440,8 +4194,6 @@ snapshots:
       call-bound: 1.0.3
       get-intrinsic: 1.2.6
 
-  is-arrayish@0.3.2: {}
-
   is-async-function@2.0.0:
     dependencies:
       has-tostringtag: 1.0.2
@@ -5081,8 +4833,6 @@ snapshots:
 
   semver@7.6.3: {}
 
-  semver@7.7.2: {}
-
   set-function-length@1.2.2:
     dependencies:
       define-data-property: 1.1.4
@@ -5099,34 +4849,6 @@ snapshots:
       functions-have-names: 1.2.3
       has-property-descriptors: 1.0.2
 
-  sharp@0.34.2:
-    dependencies:
-      color: 4.2.3
-      detect-libc: 2.0.4
-      semver: 7.7.2
-    optionalDependencies:
-      '@img/sharp-darwin-arm64': 0.34.2
-      '@img/sharp-darwin-x64': 0.34.2
-      '@img/sharp-libvips-darwin-arm64': 1.1.0
-      '@img/sharp-libvips-darwin-x64': 1.1.0
-      '@img/sharp-libvips-linux-arm': 1.1.0
-      '@img/sharp-libvips-linux-arm64': 1.1.0
-      '@img/sharp-libvips-linux-ppc64': 1.1.0
-      '@img/sharp-libvips-linux-s390x': 1.1.0
-      '@img/sharp-libvips-linux-x64': 1.1.0
-      '@img/sharp-libvips-linuxmusl-arm64': 1.1.0
-      '@img/sharp-libvips-linuxmusl-x64': 1.1.0
-      '@img/sharp-linux-arm': 0.34.2
-      '@img/sharp-linux-arm64': 0.34.2
-      '@img/sharp-linux-s390x': 0.34.2
-      '@img/sharp-linux-x64': 0.34.2
-      '@img/sharp-linuxmusl-arm64': 0.34.2
-      '@img/sharp-linuxmusl-x64': 0.34.2
-      '@img/sharp-wasm32': 0.34.2
-      '@img/sharp-win32-arm64': 0.34.2
-      '@img/sharp-win32-ia32': 0.34.2
-      '@img/sharp-win32-x64': 0.34.2
-
   shebang-command@2.0.0:
     dependencies:
       shebang-regex: 3.0.0
@@ -5163,10 +4885,6 @@ snapshots:
 
   signal-exit@4.1.0: {}
 
-  simple-swizzle@0.2.2:
-    dependencies:
-      is-arrayish: 0.3.2
-
   sirv@2.0.4:
     dependencies:
       '@polka/url': 1.0.0-next.29
@@ -5344,12 +5062,6 @@ snapshots:
 
   tslib@2.8.1: {}
 
-  twebp2@0.0.1-beta.8:
-    dependencies:
-      chokidar: 4.0.3
-      colors: 1.4.0
-      sharp: 0.34.2
-
   type-check@0.4.0:
     dependencies:
       prelude-ls: 1.2.1

+ 1 - 1
public/firebase-messaging-sw.js → public/scripts/firebase-messaging-sw.js

@@ -11,7 +11,7 @@ class CustomPushEvent extends Event {
 if ('serviceWorker' in navigator) {
   importScripts('https://www.gstatic.com/firebasejs/10.13.2/firebase-app-compat.js');
   importScripts('https://www.gstatic.com/firebasejs/10.13.2/firebase-messaging-compat.js');
-  importScripts('swenv.js')
+  importScripts('./swenv.js')
   navigator.serviceWorker.register('./firebase-messaging-sw.js').then(function (reg) {
   firebase.initializeApp({
     apiKey: process.env.NEXT_PUBLIC_FIREBASE_APIKEY,

+ 574 - 0
public/scripts/pomelo-client-json.js

@@ -0,0 +1,574 @@
+(function() {
+  function Emitter(obj) {
+    if (obj) return mixin(obj);
+  }
+  /**
+   * Mixin the emitter properties.
+   *
+   * @param {Object} obj
+   * @return {Object}
+   * @api private
+   */
+
+  function mixin(obj) {
+    for (var key in Emitter.prototype) {
+      obj[key] = Emitter.prototype[key];
+    }
+    return obj;
+  }
+
+  /**
+   * Listen on the given `event` with `fn`.
+   *
+   * @param {String} event
+   * @param {Function} fn
+   * @return {Emitter}
+   * @api public
+   */
+
+  Emitter.prototype.on =
+    Emitter.prototype.addEventListener = function(event, fn){
+      this._callbacks = this._callbacks || {};
+      (this._callbacks[event] = this._callbacks[event] || [])
+        .push(fn);
+      return this;
+    };
+
+  /**
+   * Adds an `event` listener that will be invoked a single
+   * time then automatically removed.
+   *
+   * @param {String} event
+   * @param {Function} fn
+   * @return {Emitter}
+   * @api public
+   */
+
+  Emitter.prototype.once = function(event, fn){
+    var self = this;
+    this._callbacks = this._callbacks || {};
+
+    function on() {
+      self.off(event, on);
+      fn.apply(this, arguments);
+    }
+
+    on.fn = fn;
+    this.on(event, on);
+    return this;
+  };
+
+  /**
+   * Remove the given callback for `event` or all
+   * registered callbacks.
+   *
+   * @param {String} event
+   * @param {Function} fn
+   * @return {Emitter}
+   * @api public
+   */
+
+  Emitter.prototype.off =
+    Emitter.prototype.removeListener =
+      Emitter.prototype.removeAllListeners =
+        Emitter.prototype.removeEventListener = function(event, fn){
+          this._callbacks = this._callbacks || {};
+
+          // all
+          if (0 == arguments.length) {
+            this._callbacks = {};
+            return this;
+          }
+
+          // specific event
+          var callbacks = this._callbacks[event];
+          if (!callbacks) return this;
+
+          // remove all handlers
+          if (1 == arguments.length) {
+            delete this._callbacks[event];
+            return this;
+          }
+
+          // remove specific handler
+          var cb;
+          for (var i = 0; i < callbacks.length; i++) {
+            cb = callbacks[i];
+            if (cb === fn || cb.fn === fn) {
+              callbacks.splice(i, 1);
+              break;
+            }
+          }
+          return this;
+        };
+
+  /**
+   * Emit `event` with the given args.
+   *
+   * @param {String} event
+   * @param {Mixed} ...
+   * @return {Emitter}
+   */
+
+  Emitter.prototype.emit = function(event){
+    this._callbacks = this._callbacks || {};
+    var args = [].slice.call(arguments, 1)
+      , callbacks = this._callbacks[event];
+
+    if (callbacks) {
+      callbacks = callbacks.slice(0);
+      for (var i = 0, len = callbacks.length; i < len; ++i) {
+        callbacks[i].apply(this, args);
+      }
+    }
+
+    return this;
+  };
+
+  /**
+   * Return array of callbacks for `event`.
+   *
+   * @param {String} event
+   * @return {Array}
+   * @api public
+   */
+
+  Emitter.prototype.listeners = function(event){
+    this._callbacks = this._callbacks || {};
+    return this._callbacks[event] || [];
+  };
+
+  /**
+   * Check if this emitter has `event` handlers.
+   *
+   * @param {String} event
+   * @return {Boolean}
+   * @api public
+   */
+
+  Emitter.prototype.hasListeners = function(event){
+    return !! this.listeners(event).length;
+  };
+  var JS_WS_CLIENT_TYPE = 'js-websocket';
+  var JS_WS_CLIENT_VERSION = '0.0.1';
+
+  var Protocol = window.Protocol;
+  var decodeIO_encoder = null;
+  var decodeIO_decoder = null;
+  var Package = Protocol.Package;
+  var Message = Protocol.Message;
+  var EventEmitter = Emitter;
+  var rsa = window.rsa;
+
+  if(typeof(window) != "undefined" && typeof(sys) != 'undefined' && sys.localStorage) {
+    window.localStorage = sys.localStorage;
+  }
+
+  var RES_OK = 200;
+  var RES_FAIL = 500;
+  var RES_OLD_CLIENT = 501;
+
+  if (typeof Object.create !== 'function') {
+    Object.create = function (o) {
+      function F() {}
+      F.prototype = o;
+      return new F();
+    };
+  }
+
+  var root = window;
+  var pomelo = Object.create(EventEmitter.prototype); // object extend from object
+  root.pomelo = pomelo;
+  var socket = null;
+  var reqId = 0;
+  var callbacks = {};
+  var handlers = {};
+  //Map from request id to route
+  var routeMap = {};
+  var dict = {};    // route string to code
+  var abbrs = {};   // code to route string
+
+  var heartbeatInterval = 0;
+  var heartbeatTimeout = 0;
+  var nextHeartbeatTimeout = 0;
+  var gapThreshold = 100;   // heartbeat gap threashold
+  var heartbeatId = null;
+  var heartbeatTimeoutId = null;
+  var handshakeCallback = null;
+
+  var decode = null;
+  var encode = null;
+
+  var reconnect = false;
+  var reconncetTimer = null;
+  var reconnectUrl = null;
+  var reconnectAttempts = 0;
+  var reconnectionDelay = 5000;
+  var DEFAULT_MAX_RECONNECT_ATTEMPTS = 10;
+
+  var useCrypto;
+
+  var handshakeBuffer = {
+    'sys': {
+      type: JS_WS_CLIENT_TYPE,
+      version: JS_WS_CLIENT_VERSION,
+      rsa: {}
+    },
+    'user': {
+    }
+  };
+
+  var initCallback = null;
+
+  pomelo.init = function(params, cb) {
+    initCallback = cb;
+    var host = params.host;
+    var port = params.port;
+    var path = params.path;
+
+    encode = params.encode || defaultEncode;
+    decode = params.decode || defaultDecode;
+
+    var url = 'ws://' + host;
+    if(port) {
+      url +=  ':' + port;
+    }
+
+    if(path) {
+      url += path;
+    }
+
+    handshakeBuffer.user = params.user;
+    if(params.encrypt) {
+      useCrypto = true;
+      rsa.generate(1024, "10001");
+      var data = {
+        rsa_n: rsa.n.toString(16),
+        rsa_e: rsa.e
+      };
+      handshakeBuffer.sys.rsa = data;
+    }
+    handshakeCallback = params.handshakeCallback || heartbeat;
+    connect(params, url, cb);
+  };
+
+  var defaultDecode = pomelo.decode = function(data) {
+    var msg = Message.decode(data);
+
+    if(msg.id > 0){
+      msg.route = routeMap[msg.id];
+      delete routeMap[msg.id];
+      if(!msg.route){
+        return;
+      }
+    }
+
+    msg.body = deCompose(msg);
+    return msg;
+  };
+
+  var defaultEncode = pomelo.encode = function(reqId, route, msg) {
+    var type = reqId ? Message.TYPE_REQUEST : Message.TYPE_NOTIFY;
+
+    if(decodeIO_encoder && decodeIO_encoder.lookup(route)) {
+      var Builder = decodeIO_encoder.build(route);
+      msg = new Builder(msg).encodeNB();
+    } else {
+      msg = Protocol.strencode(JSON.stringify(msg));
+    }
+
+    var compressRoute = 0;
+    if(dict && dict[route]) {
+      route = dict[route];
+      compressRoute = 1;
+    }
+
+    return Message.encode(reqId, type, compressRoute, route, msg);
+  };
+
+  var connect = function(params, url, cb) {
+    console.log('connect to ' + url);
+
+    var params = params || {};
+    var maxReconnectAttempts = params.maxReconnectAttempts || DEFAULT_MAX_RECONNECT_ATTEMPTS;
+    reconnectUrl = url;
+
+    var onopen = function(event) {
+      if(!!reconnect) {
+        pomelo.emit('reconnect');
+      }
+      reset();
+      var obj = Package.encode(Package.TYPE_HANDSHAKE, Protocol.strencode(JSON.stringify(handshakeBuffer)));
+      send(obj);
+    };
+    var onmessage = function(event) {
+      processPackage(Package.decode(event.data), cb);
+      // new package arrived, update the heartbeat timeout
+      if(heartbeatTimeout) {
+        nextHeartbeatTimeout = Date.now() + heartbeatTimeout;
+      }
+    };
+    var onerror = function(event) {
+      pomelo.emit('io-error', event);
+      console.error('socket error: ', event);
+    };
+    var onclose = function(event) {
+      pomelo.emit('close',event);
+      pomelo.emit('disconnect', event);
+      console.log('socket close: ', event);
+      if(!!params.reconnect && reconnectAttempts < maxReconnectAttempts) {
+        reconnect = true;
+        reconnectAttempts++;
+        reconncetTimer = setTimeout(function() {
+          connect(params, reconnectUrl, cb);
+        }, reconnectionDelay);
+        reconnectionDelay *= 2;
+      }
+    };
+    socket = new WebSocket(url);
+    socket.binaryType = 'arraybuffer';
+    socket.onopen = onopen;
+    socket.onmessage = onmessage;
+    socket.onerror = onerror;
+    socket.onclose = onclose;
+  };
+
+  pomelo.disconnect = function() {
+    if(socket) {
+      if(socket.disconnect) socket.disconnect();
+      if(socket.close) socket.close();
+      console.log('disconnect');
+      socket = null;
+    }
+
+    if(heartbeatId) {
+      clearTimeout(heartbeatId);
+      heartbeatId = null;
+    }
+    if(heartbeatTimeoutId) {
+      clearTimeout(heartbeatTimeoutId);
+      heartbeatTimeoutId = null;
+    }
+  };
+
+  var reset = function() {
+    reconnect = false;
+    reconnectionDelay = 1000 * 5;
+    reconnectAttempts = 0;
+    clearTimeout(reconncetTimer);
+  };
+
+  pomelo.request = function(route, msg, cb) {
+    if(arguments.length === 2 && typeof msg === 'function') {
+      cb = msg;
+      msg = {};
+    } else {
+      msg = msg || {};
+    }
+    route = route || msg.route;
+    if(!route) {
+      return;
+    }
+
+    reqId++;
+    sendMessage(reqId, route, msg);
+
+    callbacks[reqId] = cb;
+    routeMap[reqId] = route;
+  };
+
+  pomelo.notify = function(route, msg) {
+    msg = msg || {};
+    sendMessage(0, route, msg);
+  };
+
+  var sendMessage = function(reqId, route, msg) {
+    if(useCrypto) {
+      msg = JSON.stringify(msg);
+      var sig = rsa.signString(msg, "sha256");
+      msg = JSON.parse(msg);
+      msg['__crypto__'] = sig;
+    }
+
+    if(encode) {
+      msg = encode(reqId, route, msg);
+    }
+
+    var packet = Package.encode(Package.TYPE_DATA, msg);
+    send(packet);
+  };
+
+  var send = function(packet) {
+    socket.send(packet.buffer);
+  };
+
+  var handler = {};
+
+  var heartbeat = function(data) {
+    if(!heartbeatInterval) {
+      // no heartbeat
+      return;
+    }
+
+    var obj = Package.encode(Package.TYPE_HEARTBEAT);
+    if(heartbeatTimeoutId) {
+      clearTimeout(heartbeatTimeoutId);
+      heartbeatTimeoutId = null;
+    }
+
+    if(heartbeatId) {
+      // already in a heartbeat interval
+      return;
+    }
+    heartbeatId = setTimeout(function() {
+      heartbeatId = null;
+      send(obj);
+      console.log("send heartbeat");
+
+      nextHeartbeatTimeout = Date.now() + heartbeatTimeout;
+      heartbeatTimeoutId = setTimeout(heartbeatTimeoutCb, heartbeatTimeout);
+    }, heartbeatInterval);
+  };
+
+  var heartbeatTimeoutCb = function() {
+    var gap = nextHeartbeatTimeout - Date.now();
+    if(gap > gapThreshold) {
+      heartbeatTimeoutId = setTimeout(heartbeatTimeoutCb, gap);
+    } else {
+      console.error('server heartbeat timeout');
+      pomelo.emit('heartbeat timeout');
+      pomelo.disconnect();
+    }
+  };
+
+  var handshake = function(data) {
+    data = JSON.parse(Protocol.strdecode(data));
+    if(data.code === RES_OLD_CLIENT) {
+      pomelo.emit('error', 'client version not fullfill');
+      return;
+    }
+
+    if(data.code !== RES_OK) {
+      pomelo.emit('error', 'handshake fail');
+      return;
+    }
+
+    handshakeInit(data);
+
+    var obj = Package.encode(Package.TYPE_HANDSHAKE_ACK);
+    send(obj);
+    if(initCallback) {
+      initCallback(socket);
+    }
+  };
+
+  var onData = function(data) {
+    var msg = data;
+    if(decode) {
+      msg = decode(msg);
+    }
+    processMessage(pomelo, msg);
+  };
+
+  var onKick = function(data) {
+    data = JSON.parse(Protocol.strdecode(data));
+    pomelo.emit('onKick', data);
+  };
+
+  handlers[Package.TYPE_HANDSHAKE] = handshake;
+  handlers[Package.TYPE_HEARTBEAT] = heartbeat;
+  handlers[Package.TYPE_DATA] = onData;
+  handlers[Package.TYPE_KICK] = onKick;
+
+  var processPackage = function(msgs) {
+    if(Array.isArray(msgs)) {
+      for(var i=0; i<msgs.length; i++) {
+        var msg = msgs[i];
+        handlers[msg.type](msg.body);
+      }
+    } else {
+      handlers[msgs.type](msgs.body);
+    }
+  };
+
+  var processMessage = function(pomelo, msg) {
+    if(!msg.id) {
+      // server push message
+      pomelo.emit(msg.route, msg.body);
+      return;
+    }
+
+    //if have a id then find the callback function with the request
+    var cb = callbacks[msg.id];
+
+    delete callbacks[msg.id];
+    if(typeof cb !== 'function') {
+      return;
+    }
+
+    cb(msg.body);
+
+  };
+
+  var processMessageBatch = function(pomelo, msgs) {
+    for(var i=0, l=msgs.length; i<l; i++) {
+      processMessage(pomelo, msgs[i]);
+    }
+  };
+
+  var deCompose = function(msg) {
+    var route = msg.route;
+
+    //Decompose route from dict
+    if(msg.compressRoute) {
+      if(!abbrs[route]){
+        return {};
+      }
+
+      route = msg.route = abbrs[route];
+    }
+
+    if(decodeIO_decoder && decodeIO_decoder.lookup(route)) {
+      return decodeIO_decoder.build(route).decode(msg.body);
+    } else {
+      return JSON.parse(Protocol.strdecode(msg.body));
+    }
+
+    return msg;
+  };
+
+  var handshakeInit = function(data) {
+    if(data.sys && data.sys.heartbeat) {
+      heartbeatInterval = data.sys.heartbeat * 1000;   // heartbeat interval
+      heartbeatTimeout = heartbeatInterval * 2;        // max heartbeat timeout
+    } else {
+      heartbeatInterval = 0;
+      heartbeatTimeout = 0;
+    }
+
+    initData(data);
+
+    if(typeof handshakeCallback === 'function') {
+      handshakeCallback(data.user);
+    }
+  };
+
+  //Initilize data used in pomelo client
+  var initData = function(data) {
+    if(!data || !data.sys) {
+      return;
+    }
+    dict = data.sys.dict;
+
+    //Init compress dict
+    if(dict) {
+      dict = dict;
+      abbrs = {};
+
+      for(var route in dict) {
+        abbrs[dict[route]] = route;
+      }
+    }
+
+    window.pomelo = pomelo;
+  }})();

+ 349 - 0
public/scripts/protocol.js

@@ -0,0 +1,349 @@
+(function (exports, ByteArray, global) {
+  var Protocol = exports;
+
+  var PKG_HEAD_BYTES = 4;
+  var MSG_FLAG_BYTES = 1;
+  var MSG_ROUTE_CODE_BYTES = 2;
+  var MSG_ID_MAX_BYTES = 5;
+  var MSG_ROUTE_LEN_BYTES = 1;
+
+  var MSG_ROUTE_CODE_MAX = 0xffff;
+
+  var MSG_COMPRESS_ROUTE_MASK = 0x1;
+  var MSG_TYPE_MASK = 0x7;
+
+  var Package = Protocol.Package = {};
+  var Message = Protocol.Message = {};
+
+  Package.TYPE_HANDSHAKE = 1;
+  Package.TYPE_HANDSHAKE_ACK = 2;
+  Package.TYPE_HEARTBEAT = 3;
+  Package.TYPE_DATA = 4;
+  Package.TYPE_KICK = 5;
+
+  Message.TYPE_REQUEST = 0;
+  Message.TYPE_NOTIFY = 1;
+  Message.TYPE_RESPONSE = 2;
+  Message.TYPE_PUSH = 3;
+
+  /**
+   * pomele client encode
+   * id message id;
+   * route message route
+   * msg message body
+   * socketio current support string
+   */
+  Protocol.strencode = function(str) {
+    var byteArray = new ByteArray(str.length * 3);
+    var offset = 0;
+    for(var i = 0; i < str.length; i++){
+      var charCode = str.charCodeAt(i);
+      var codes = null;
+      if(charCode <= 0x7f){
+        codes = [charCode];
+      }else if(charCode <= 0x7ff){
+        codes = [0xc0|(charCode>>6), 0x80|(charCode & 0x3f)];
+      }else{
+        codes = [0xe0|(charCode>>12), 0x80|((charCode & 0xfc0)>>6), 0x80|(charCode & 0x3f)];
+      }
+      for(var j = 0; j < codes.length; j++){
+        byteArray[offset] = codes[j];
+        ++offset;
+      }
+    }
+    var _buffer = new ByteArray(offset);
+    copyArray(_buffer, 0, byteArray, 0, offset);
+    return _buffer;
+  };
+
+  /**
+   * client decode
+   * msg String data
+   * return Message Object
+   */
+  Protocol.strdecode = function(buffer) {
+    var bytes = new ByteArray(buffer);
+    var array = [];
+    var offset = 0;
+    var charCode = 0;
+    var end = bytes.length;
+    while(offset < end){
+      if(bytes[offset] < 128){
+        charCode = bytes[offset];
+        offset += 1;
+      }else if(bytes[offset] < 224){
+        charCode = ((bytes[offset] & 0x3f)<<6) + (bytes[offset+1] & 0x3f);
+        offset += 2;
+      }else{
+        charCode = ((bytes[offset] & 0x0f)<<12) + ((bytes[offset+1] & 0x3f)<<6) + (bytes[offset+2] & 0x3f);
+        offset += 3;
+      }
+      array.push(charCode);
+    }
+    return String.fromCharCode.apply(null, array);
+  };
+
+  /**
+   * Package protocol encode.
+   *
+   * Pomelo package format:
+   * +------+-------------+------------------+
+   * | type | body length |       body       |
+   * +------+-------------+------------------+
+   *
+   * Head: 4bytes
+   *   0: package type,
+   *      1 - handshake,
+   *      2 - handshake ack,
+   *      3 - heartbeat,
+   *      4 - data
+   *      5 - kick
+   *   1 - 3: big-endian body length
+   * Body: body length bytes
+   *
+   * @param  {Number}    type   package type
+   * @param  {ByteArray} body   body content in bytes
+   * @return {ByteArray}        new byte array that contains encode result
+   */
+  Package.encode = function(type, body){
+    var length = body ? body.length : 0;
+    var buffer = new ByteArray(PKG_HEAD_BYTES + length);
+    var index = 0;
+    buffer[index++] = type & 0xff;
+    buffer[index++] = (length >> 16) & 0xff;
+    buffer[index++] = (length >> 8) & 0xff;
+    buffer[index++] = length & 0xff;
+    if(body) {
+      copyArray(buffer, index, body, 0, length);
+    }
+    return buffer;
+  };
+
+  /**
+   * Package protocol decode.
+   * See encode for package format.
+   *
+   * @param  {ByteArray} buffer byte array containing package content
+   * @return {Object}           {type: package type, buffer: body byte array}
+   */
+  Package.decode = function(buffer){
+    var offset = 0;
+    var bytes = new ByteArray(buffer);
+    var length = 0;
+    var rs = [];
+    while(offset < bytes.length) {
+      var type = bytes[offset++];
+      length = ((bytes[offset++]) << 16 | (bytes[offset++]) << 8 | bytes[offset++]) >>> 0;
+      var body = length ? new ByteArray(length) : null;
+      copyArray(body, 0, bytes, offset, length);
+      offset += length;
+      rs.push({'type': type, 'body': body});
+    }
+    return rs.length === 1 ? rs[0]: rs;
+  };
+
+  /**
+   * Message protocol encode.
+   *
+   * @param  {Number} id            message id
+   * @param  {Number} type          message type
+   * @param  {Number} compressRoute whether compress route
+   * @param  {Number|String} route  route code or route string
+   * @param  {Buffer} msg           message body bytes
+   * @return {Buffer}               encode result
+   */
+  Message.encode = function(id, type, compressRoute, route, msg){
+    // caculate message max length
+    var idBytes = msgHasId(type) ? caculateMsgIdBytes(id) : 0;
+    var msgLen = MSG_FLAG_BYTES + idBytes;
+
+    if(msgHasRoute(type)) {
+      if(compressRoute) {
+        if(typeof route !== 'number'){
+          throw new Error('error flag for number route!');
+        }
+        msgLen += MSG_ROUTE_CODE_BYTES;
+      } else {
+        msgLen += MSG_ROUTE_LEN_BYTES;
+        if(route) {
+          route = Protocol.strencode(route);
+          if(route.length>255) {
+            throw new Error('route maxlength is overflow');
+          }
+          msgLen += route.length;
+        }
+      }
+    }
+
+    if(msg) {
+      msgLen += msg.length;
+    }
+
+    var buffer = new ByteArray(msgLen);
+    var offset = 0;
+
+    // add flag
+    offset = encodeMsgFlag(type, compressRoute, buffer, offset);
+
+    // add message id
+    if(msgHasId(type)) {
+      offset = encodeMsgId(id, buffer, offset);
+    }
+
+    // add route
+    if(msgHasRoute(type)) {
+      offset = encodeMsgRoute(compressRoute, route, buffer, offset);
+    }
+
+    // add body
+    if(msg) {
+      offset = encodeMsgBody(msg, buffer, offset);
+    }
+
+    return buffer;
+  };
+
+  /**
+   * Message protocol decode.
+   *
+   * @param  {Buffer|Uint8Array} buffer message bytes
+   * @return {Object}            message object
+   */
+  Message.decode = function(buffer) {
+    var bytes =  new ByteArray(buffer);
+    var bytesLen = bytes.length || bytes.byteLength;
+    var offset = 0;
+    var id = 0;
+    var route = null;
+
+    // parse flag
+    var flag = bytes[offset++];
+    var compressRoute = flag & MSG_COMPRESS_ROUTE_MASK;
+    var type = (flag >> 1) & MSG_TYPE_MASK;
+
+    // parse id
+    if(msgHasId(type)) {
+      var m = parseInt(bytes[offset]);
+      var i = 0;
+      do{
+        var m = parseInt(bytes[offset]);
+        id = id + ((m & 0x7f) * Math.pow(2,(7*i)));
+        offset++;
+        i++;
+      }while(m >= 128);
+    }
+
+    // parse route
+    if(msgHasRoute(type)) {
+      if(compressRoute) {
+        route = (bytes[offset++]) << 8 | bytes[offset++];
+      } else {
+        var routeLen = bytes[offset++];
+        if(routeLen) {
+          route = new ByteArray(routeLen);
+          copyArray(route, 0, bytes, offset, routeLen);
+          route = Protocol.strdecode(route);
+        } else {
+          route = '';
+        }
+        offset += routeLen;
+      }
+    }
+
+    // parse body
+    var bodyLen = bytesLen - offset;
+    var body = new ByteArray(bodyLen);
+
+    copyArray(body, 0, bytes, offset, bodyLen);
+
+    return {'id': id, 'type': type, 'compressRoute': compressRoute,
+            'route': route, 'body': body};
+  };
+
+  var copyArray = function(dest, doffset, src, soffset, length) {
+    if('function' === typeof src.copy) {
+      // Buffer
+      src.copy(dest, doffset, soffset, soffset + length);
+    } else {
+      // Uint8Array
+      for(var index=0; index<length; index++){
+        dest[doffset++] = src[soffset++];
+      }
+    }
+  };
+
+  var msgHasId = function(type) {
+    return type === Message.TYPE_REQUEST || type === Message.TYPE_RESPONSE;
+  };
+
+  var msgHasRoute = function(type) {
+    return type === Message.TYPE_REQUEST || type === Message.TYPE_NOTIFY ||
+           type === Message.TYPE_PUSH;
+  };
+
+  var caculateMsgIdBytes = function(id) {
+    var len = 0;
+    do {
+      len += 1;
+      id >>= 7;
+    } while(id > 0);
+    return len;
+  };
+
+  var encodeMsgFlag = function(type, compressRoute, buffer, offset) {
+    if(type !== Message.TYPE_REQUEST && type !== Message.TYPE_NOTIFY &&
+       type !== Message.TYPE_RESPONSE && type !== Message.TYPE_PUSH) {
+      throw new Error('unkonw message type: ' + type);
+    }
+
+    buffer[offset] = (type << 1) | (compressRoute ? 1 : 0);
+
+    return offset + MSG_FLAG_BYTES;
+  };
+
+  var encodeMsgId = function(id, buffer, offset) {
+    do{
+      var tmp = id % 128;
+      var next = Math.floor(id/128);
+
+      if(next !== 0){
+        tmp = tmp + 128;
+      }
+      buffer[offset++] = tmp;
+
+      id = next;
+    } while(id !== 0);
+
+    return offset;
+  };
+
+  var encodeMsgRoute = function(compressRoute, route, buffer, offset) {
+    if (compressRoute) {
+      if(route > MSG_ROUTE_CODE_MAX){
+        throw new Error('route number is overflow');
+      }
+
+      buffer[offset++] = (route >> 8) & 0xff;
+      buffer[offset++] = route & 0xff;
+    } else {
+      if(route) {
+        buffer[offset++] = route.length & 0xff;
+        copyArray(buffer, offset, route, 0, route.length);
+        offset += route.length;
+      } else {
+        buffer[offset++] = 0;
+      }
+    }
+
+    return offset;
+  };
+
+  var encodeMsgBody = function(msg, buffer, offset) {
+    copyArray(buffer, offset, msg, 0, msg.length);
+    return offset + msg.length;
+  };
+
+  if(typeof(window) != "undefined") {
+    window.Protocol = Protocol;
+  }
+})(typeof(window)=="undefined" ? module.exports : (this.Protocol = {}),typeof(window)=="undefined"  ? Buffer : Uint8Array, this);

+ 0 - 0
public/swenv.js → public/scripts/swenv.js


+ 1 - 1
public_original/firebase-messaging-sw.js → public_original/scripts/firebase-messaging-sw.js

@@ -11,7 +11,7 @@ class CustomPushEvent extends Event {
 if ('serviceWorker' in navigator) {
   importScripts('https://www.gstatic.com/firebasejs/10.13.2/firebase-app-compat.js');
   importScripts('https://www.gstatic.com/firebasejs/10.13.2/firebase-messaging-compat.js');
-  importScripts('swenv.js')
+  importScripts('./swenv.js')
   navigator.serviceWorker.register('./firebase-messaging-sw.js').then(function (reg) {
   firebase.initializeApp({
     apiKey: process.env.NEXT_PUBLIC_FIREBASE_APIKEY,

+ 574 - 0
public_original/scripts/pomelo-client-json.js

@@ -0,0 +1,574 @@
+(function() {
+  function Emitter(obj) {
+    if (obj) return mixin(obj);
+  }
+  /**
+   * Mixin the emitter properties.
+   *
+   * @param {Object} obj
+   * @return {Object}
+   * @api private
+   */
+
+  function mixin(obj) {
+    for (var key in Emitter.prototype) {
+      obj[key] = Emitter.prototype[key];
+    }
+    return obj;
+  }
+
+  /**
+   * Listen on the given `event` with `fn`.
+   *
+   * @param {String} event
+   * @param {Function} fn
+   * @return {Emitter}
+   * @api public
+   */
+
+  Emitter.prototype.on =
+    Emitter.prototype.addEventListener = function(event, fn){
+      this._callbacks = this._callbacks || {};
+      (this._callbacks[event] = this._callbacks[event] || [])
+        .push(fn);
+      return this;
+    };
+
+  /**
+   * Adds an `event` listener that will be invoked a single
+   * time then automatically removed.
+   *
+   * @param {String} event
+   * @param {Function} fn
+   * @return {Emitter}
+   * @api public
+   */
+
+  Emitter.prototype.once = function(event, fn){
+    var self = this;
+    this._callbacks = this._callbacks || {};
+
+    function on() {
+      self.off(event, on);
+      fn.apply(this, arguments);
+    }
+
+    on.fn = fn;
+    this.on(event, on);
+    return this;
+  };
+
+  /**
+   * Remove the given callback for `event` or all
+   * registered callbacks.
+   *
+   * @param {String} event
+   * @param {Function} fn
+   * @return {Emitter}
+   * @api public
+   */
+
+  Emitter.prototype.off =
+    Emitter.prototype.removeListener =
+      Emitter.prototype.removeAllListeners =
+        Emitter.prototype.removeEventListener = function(event, fn){
+          this._callbacks = this._callbacks || {};
+
+          // all
+          if (0 == arguments.length) {
+            this._callbacks = {};
+            return this;
+          }
+
+          // specific event
+          var callbacks = this._callbacks[event];
+          if (!callbacks) return this;
+
+          // remove all handlers
+          if (1 == arguments.length) {
+            delete this._callbacks[event];
+            return this;
+          }
+
+          // remove specific handler
+          var cb;
+          for (var i = 0; i < callbacks.length; i++) {
+            cb = callbacks[i];
+            if (cb === fn || cb.fn === fn) {
+              callbacks.splice(i, 1);
+              break;
+            }
+          }
+          return this;
+        };
+
+  /**
+   * Emit `event` with the given args.
+   *
+   * @param {String} event
+   * @param {Mixed} ...
+   * @return {Emitter}
+   */
+
+  Emitter.prototype.emit = function(event){
+    this._callbacks = this._callbacks || {};
+    var args = [].slice.call(arguments, 1)
+      , callbacks = this._callbacks[event];
+
+    if (callbacks) {
+      callbacks = callbacks.slice(0);
+      for (var i = 0, len = callbacks.length; i < len; ++i) {
+        callbacks[i].apply(this, args);
+      }
+    }
+
+    return this;
+  };
+
+  /**
+   * Return array of callbacks for `event`.
+   *
+   * @param {String} event
+   * @return {Array}
+   * @api public
+   */
+
+  Emitter.prototype.listeners = function(event){
+    this._callbacks = this._callbacks || {};
+    return this._callbacks[event] || [];
+  };
+
+  /**
+   * Check if this emitter has `event` handlers.
+   *
+   * @param {String} event
+   * @return {Boolean}
+   * @api public
+   */
+
+  Emitter.prototype.hasListeners = function(event){
+    return !! this.listeners(event).length;
+  };
+  var JS_WS_CLIENT_TYPE = 'js-websocket';
+  var JS_WS_CLIENT_VERSION = '0.0.1';
+
+  var Protocol = window.Protocol;
+  var decodeIO_encoder = null;
+  var decodeIO_decoder = null;
+  var Package = Protocol.Package;
+  var Message = Protocol.Message;
+  var EventEmitter = Emitter;
+  var rsa = window.rsa;
+
+  if(typeof(window) != "undefined" && typeof(sys) != 'undefined' && sys.localStorage) {
+    window.localStorage = sys.localStorage;
+  }
+
+  var RES_OK = 200;
+  var RES_FAIL = 500;
+  var RES_OLD_CLIENT = 501;
+
+  if (typeof Object.create !== 'function') {
+    Object.create = function (o) {
+      function F() {}
+      F.prototype = o;
+      return new F();
+    };
+  }
+
+  var root = window;
+  var pomelo = Object.create(EventEmitter.prototype); // object extend from object
+  root.pomelo = pomelo;
+  var socket = null;
+  var reqId = 0;
+  var callbacks = {};
+  var handlers = {};
+  //Map from request id to route
+  var routeMap = {};
+  var dict = {};    // route string to code
+  var abbrs = {};   // code to route string
+
+  var heartbeatInterval = 0;
+  var heartbeatTimeout = 0;
+  var nextHeartbeatTimeout = 0;
+  var gapThreshold = 100;   // heartbeat gap threashold
+  var heartbeatId = null;
+  var heartbeatTimeoutId = null;
+  var handshakeCallback = null;
+
+  var decode = null;
+  var encode = null;
+
+  var reconnect = false;
+  var reconncetTimer = null;
+  var reconnectUrl = null;
+  var reconnectAttempts = 0;
+  var reconnectionDelay = 5000;
+  var DEFAULT_MAX_RECONNECT_ATTEMPTS = 10;
+
+  var useCrypto;
+
+  var handshakeBuffer = {
+    'sys': {
+      type: JS_WS_CLIENT_TYPE,
+      version: JS_WS_CLIENT_VERSION,
+      rsa: {}
+    },
+    'user': {
+    }
+  };
+
+  var initCallback = null;
+
+  pomelo.init = function(params, cb) {
+    initCallback = cb;
+    var host = params.host;
+    var port = params.port;
+    var path = params.path;
+
+    encode = params.encode || defaultEncode;
+    decode = params.decode || defaultDecode;
+
+    var url = 'ws://' + host;
+    if(port) {
+      url +=  ':' + port;
+    }
+
+    if(path) {
+      url += path;
+    }
+
+    handshakeBuffer.user = params.user;
+    if(params.encrypt) {
+      useCrypto = true;
+      rsa.generate(1024, "10001");
+      var data = {
+        rsa_n: rsa.n.toString(16),
+        rsa_e: rsa.e
+      };
+      handshakeBuffer.sys.rsa = data;
+    }
+    handshakeCallback = params.handshakeCallback || heartbeat;
+    connect(params, url, cb);
+  };
+
+  var defaultDecode = pomelo.decode = function(data) {
+    var msg = Message.decode(data);
+
+    if(msg.id > 0){
+      msg.route = routeMap[msg.id];
+      delete routeMap[msg.id];
+      if(!msg.route){
+        return;
+      }
+    }
+
+    msg.body = deCompose(msg);
+    return msg;
+  };
+
+  var defaultEncode = pomelo.encode = function(reqId, route, msg) {
+    var type = reqId ? Message.TYPE_REQUEST : Message.TYPE_NOTIFY;
+
+    if(decodeIO_encoder && decodeIO_encoder.lookup(route)) {
+      var Builder = decodeIO_encoder.build(route);
+      msg = new Builder(msg).encodeNB();
+    } else {
+      msg = Protocol.strencode(JSON.stringify(msg));
+    }
+
+    var compressRoute = 0;
+    if(dict && dict[route]) {
+      route = dict[route];
+      compressRoute = 1;
+    }
+
+    return Message.encode(reqId, type, compressRoute, route, msg);
+  };
+
+  var connect = function(params, url, cb) {
+    console.log('connect to ' + url);
+
+    var params = params || {};
+    var maxReconnectAttempts = params.maxReconnectAttempts || DEFAULT_MAX_RECONNECT_ATTEMPTS;
+    reconnectUrl = url;
+
+    var onopen = function(event) {
+      if(!!reconnect) {
+        pomelo.emit('reconnect');
+      }
+      reset();
+      var obj = Package.encode(Package.TYPE_HANDSHAKE, Protocol.strencode(JSON.stringify(handshakeBuffer)));
+      send(obj);
+    };
+    var onmessage = function(event) {
+      processPackage(Package.decode(event.data), cb);
+      // new package arrived, update the heartbeat timeout
+      if(heartbeatTimeout) {
+        nextHeartbeatTimeout = Date.now() + heartbeatTimeout;
+      }
+    };
+    var onerror = function(event) {
+      pomelo.emit('io-error', event);
+      console.error('socket error: ', event);
+    };
+    var onclose = function(event) {
+      pomelo.emit('close',event);
+      pomelo.emit('disconnect', event);
+      console.log('socket close: ', event);
+      if(!!params.reconnect && reconnectAttempts < maxReconnectAttempts) {
+        reconnect = true;
+        reconnectAttempts++;
+        reconncetTimer = setTimeout(function() {
+          connect(params, reconnectUrl, cb);
+        }, reconnectionDelay);
+        reconnectionDelay *= 2;
+      }
+    };
+    socket = new WebSocket(url);
+    socket.binaryType = 'arraybuffer';
+    socket.onopen = onopen;
+    socket.onmessage = onmessage;
+    socket.onerror = onerror;
+    socket.onclose = onclose;
+  };
+
+  pomelo.disconnect = function() {
+    if(socket) {
+      if(socket.disconnect) socket.disconnect();
+      if(socket.close) socket.close();
+      console.log('disconnect');
+      socket = null;
+    }
+
+    if(heartbeatId) {
+      clearTimeout(heartbeatId);
+      heartbeatId = null;
+    }
+    if(heartbeatTimeoutId) {
+      clearTimeout(heartbeatTimeoutId);
+      heartbeatTimeoutId = null;
+    }
+  };
+
+  var reset = function() {
+    reconnect = false;
+    reconnectionDelay = 1000 * 5;
+    reconnectAttempts = 0;
+    clearTimeout(reconncetTimer);
+  };
+
+  pomelo.request = function(route, msg, cb) {
+    if(arguments.length === 2 && typeof msg === 'function') {
+      cb = msg;
+      msg = {};
+    } else {
+      msg = msg || {};
+    }
+    route = route || msg.route;
+    if(!route) {
+      return;
+    }
+
+    reqId++;
+    sendMessage(reqId, route, msg);
+
+    callbacks[reqId] = cb;
+    routeMap[reqId] = route;
+  };
+
+  pomelo.notify = function(route, msg) {
+    msg = msg || {};
+    sendMessage(0, route, msg);
+  };
+
+  var sendMessage = function(reqId, route, msg) {
+    if(useCrypto) {
+      msg = JSON.stringify(msg);
+      var sig = rsa.signString(msg, "sha256");
+      msg = JSON.parse(msg);
+      msg['__crypto__'] = sig;
+    }
+
+    if(encode) {
+      msg = encode(reqId, route, msg);
+    }
+
+    var packet = Package.encode(Package.TYPE_DATA, msg);
+    send(packet);
+  };
+
+  var send = function(packet) {
+    socket.send(packet.buffer);
+  };
+
+  var handler = {};
+
+  var heartbeat = function(data) {
+    if(!heartbeatInterval) {
+      // no heartbeat
+      return;
+    }
+
+    var obj = Package.encode(Package.TYPE_HEARTBEAT);
+    if(heartbeatTimeoutId) {
+      clearTimeout(heartbeatTimeoutId);
+      heartbeatTimeoutId = null;
+    }
+
+    if(heartbeatId) {
+      // already in a heartbeat interval
+      return;
+    }
+    heartbeatId = setTimeout(function() {
+      heartbeatId = null;
+      send(obj);
+      console.log("send heartbeat");
+
+      nextHeartbeatTimeout = Date.now() + heartbeatTimeout;
+      heartbeatTimeoutId = setTimeout(heartbeatTimeoutCb, heartbeatTimeout);
+    }, heartbeatInterval);
+  };
+
+  var heartbeatTimeoutCb = function() {
+    var gap = nextHeartbeatTimeout - Date.now();
+    if(gap > gapThreshold) {
+      heartbeatTimeoutId = setTimeout(heartbeatTimeoutCb, gap);
+    } else {
+      console.error('server heartbeat timeout');
+      pomelo.emit('heartbeat timeout');
+      pomelo.disconnect();
+    }
+  };
+
+  var handshake = function(data) {
+    data = JSON.parse(Protocol.strdecode(data));
+    if(data.code === RES_OLD_CLIENT) {
+      pomelo.emit('error', 'client version not fullfill');
+      return;
+    }
+
+    if(data.code !== RES_OK) {
+      pomelo.emit('error', 'handshake fail');
+      return;
+    }
+
+    handshakeInit(data);
+
+    var obj = Package.encode(Package.TYPE_HANDSHAKE_ACK);
+    send(obj);
+    if(initCallback) {
+      initCallback(socket);
+    }
+  };
+
+  var onData = function(data) {
+    var msg = data;
+    if(decode) {
+      msg = decode(msg);
+    }
+    processMessage(pomelo, msg);
+  };
+
+  var onKick = function(data) {
+    data = JSON.parse(Protocol.strdecode(data));
+    pomelo.emit('onKick', data);
+  };
+
+  handlers[Package.TYPE_HANDSHAKE] = handshake;
+  handlers[Package.TYPE_HEARTBEAT] = heartbeat;
+  handlers[Package.TYPE_DATA] = onData;
+  handlers[Package.TYPE_KICK] = onKick;
+
+  var processPackage = function(msgs) {
+    if(Array.isArray(msgs)) {
+      for(var i=0; i<msgs.length; i++) {
+        var msg = msgs[i];
+        handlers[msg.type](msg.body);
+      }
+    } else {
+      handlers[msgs.type](msgs.body);
+    }
+  };
+
+  var processMessage = function(pomelo, msg) {
+    if(!msg.id) {
+      // server push message
+      pomelo.emit(msg.route, msg.body);
+      return;
+    }
+
+    //if have a id then find the callback function with the request
+    var cb = callbacks[msg.id];
+
+    delete callbacks[msg.id];
+    if(typeof cb !== 'function') {
+      return;
+    }
+
+    cb(msg.body);
+
+  };
+
+  var processMessageBatch = function(pomelo, msgs) {
+    for(var i=0, l=msgs.length; i<l; i++) {
+      processMessage(pomelo, msgs[i]);
+    }
+  };
+
+  var deCompose = function(msg) {
+    var route = msg.route;
+
+    //Decompose route from dict
+    if(msg.compressRoute) {
+      if(!abbrs[route]){
+        return {};
+      }
+
+      route = msg.route = abbrs[route];
+    }
+
+    if(decodeIO_decoder && decodeIO_decoder.lookup(route)) {
+      return decodeIO_decoder.build(route).decode(msg.body);
+    } else {
+      return JSON.parse(Protocol.strdecode(msg.body));
+    }
+
+    return msg;
+  };
+
+  var handshakeInit = function(data) {
+    if(data.sys && data.sys.heartbeat) {
+      heartbeatInterval = data.sys.heartbeat * 1000;   // heartbeat interval
+      heartbeatTimeout = heartbeatInterval * 2;        // max heartbeat timeout
+    } else {
+      heartbeatInterval = 0;
+      heartbeatTimeout = 0;
+    }
+
+    initData(data);
+
+    if(typeof handshakeCallback === 'function') {
+      handshakeCallback(data.user);
+    }
+  };
+
+  //Initilize data used in pomelo client
+  var initData = function(data) {
+    if(!data || !data.sys) {
+      return;
+    }
+    dict = data.sys.dict;
+
+    //Init compress dict
+    if(dict) {
+      dict = dict;
+      abbrs = {};
+
+      for(var route in dict) {
+        abbrs[dict[route]] = route;
+      }
+    }
+
+    window.pomelo = pomelo;
+  }})();

+ 349 - 0
public_original/scripts/protocol.js

@@ -0,0 +1,349 @@
+(function (exports, ByteArray, global) {
+  var Protocol = exports;
+
+  var PKG_HEAD_BYTES = 4;
+  var MSG_FLAG_BYTES = 1;
+  var MSG_ROUTE_CODE_BYTES = 2;
+  var MSG_ID_MAX_BYTES = 5;
+  var MSG_ROUTE_LEN_BYTES = 1;
+
+  var MSG_ROUTE_CODE_MAX = 0xffff;
+
+  var MSG_COMPRESS_ROUTE_MASK = 0x1;
+  var MSG_TYPE_MASK = 0x7;
+
+  var Package = Protocol.Package = {};
+  var Message = Protocol.Message = {};
+
+  Package.TYPE_HANDSHAKE = 1;
+  Package.TYPE_HANDSHAKE_ACK = 2;
+  Package.TYPE_HEARTBEAT = 3;
+  Package.TYPE_DATA = 4;
+  Package.TYPE_KICK = 5;
+
+  Message.TYPE_REQUEST = 0;
+  Message.TYPE_NOTIFY = 1;
+  Message.TYPE_RESPONSE = 2;
+  Message.TYPE_PUSH = 3;
+
+  /**
+   * pomele client encode
+   * id message id;
+   * route message route
+   * msg message body
+   * socketio current support string
+   */
+  Protocol.strencode = function(str) {
+    var byteArray = new ByteArray(str.length * 3);
+    var offset = 0;
+    for(var i = 0; i < str.length; i++){
+      var charCode = str.charCodeAt(i);
+      var codes = null;
+      if(charCode <= 0x7f){
+        codes = [charCode];
+      }else if(charCode <= 0x7ff){
+        codes = [0xc0|(charCode>>6), 0x80|(charCode & 0x3f)];
+      }else{
+        codes = [0xe0|(charCode>>12), 0x80|((charCode & 0xfc0)>>6), 0x80|(charCode & 0x3f)];
+      }
+      for(var j = 0; j < codes.length; j++){
+        byteArray[offset] = codes[j];
+        ++offset;
+      }
+    }
+    var _buffer = new ByteArray(offset);
+    copyArray(_buffer, 0, byteArray, 0, offset);
+    return _buffer;
+  };
+
+  /**
+   * client decode
+   * msg String data
+   * return Message Object
+   */
+  Protocol.strdecode = function(buffer) {
+    var bytes = new ByteArray(buffer);
+    var array = [];
+    var offset = 0;
+    var charCode = 0;
+    var end = bytes.length;
+    while(offset < end){
+      if(bytes[offset] < 128){
+        charCode = bytes[offset];
+        offset += 1;
+      }else if(bytes[offset] < 224){
+        charCode = ((bytes[offset] & 0x3f)<<6) + (bytes[offset+1] & 0x3f);
+        offset += 2;
+      }else{
+        charCode = ((bytes[offset] & 0x0f)<<12) + ((bytes[offset+1] & 0x3f)<<6) + (bytes[offset+2] & 0x3f);
+        offset += 3;
+      }
+      array.push(charCode);
+    }
+    return String.fromCharCode.apply(null, array);
+  };
+
+  /**
+   * Package protocol encode.
+   *
+   * Pomelo package format:
+   * +------+-------------+------------------+
+   * | type | body length |       body       |
+   * +------+-------------+------------------+
+   *
+   * Head: 4bytes
+   *   0: package type,
+   *      1 - handshake,
+   *      2 - handshake ack,
+   *      3 - heartbeat,
+   *      4 - data
+   *      5 - kick
+   *   1 - 3: big-endian body length
+   * Body: body length bytes
+   *
+   * @param  {Number}    type   package type
+   * @param  {ByteArray} body   body content in bytes
+   * @return {ByteArray}        new byte array that contains encode result
+   */
+  Package.encode = function(type, body){
+    var length = body ? body.length : 0;
+    var buffer = new ByteArray(PKG_HEAD_BYTES + length);
+    var index = 0;
+    buffer[index++] = type & 0xff;
+    buffer[index++] = (length >> 16) & 0xff;
+    buffer[index++] = (length >> 8) & 0xff;
+    buffer[index++] = length & 0xff;
+    if(body) {
+      copyArray(buffer, index, body, 0, length);
+    }
+    return buffer;
+  };
+
+  /**
+   * Package protocol decode.
+   * See encode for package format.
+   *
+   * @param  {ByteArray} buffer byte array containing package content
+   * @return {Object}           {type: package type, buffer: body byte array}
+   */
+  Package.decode = function(buffer){
+    var offset = 0;
+    var bytes = new ByteArray(buffer);
+    var length = 0;
+    var rs = [];
+    while(offset < bytes.length) {
+      var type = bytes[offset++];
+      length = ((bytes[offset++]) << 16 | (bytes[offset++]) << 8 | bytes[offset++]) >>> 0;
+      var body = length ? new ByteArray(length) : null;
+      copyArray(body, 0, bytes, offset, length);
+      offset += length;
+      rs.push({'type': type, 'body': body});
+    }
+    return rs.length === 1 ? rs[0]: rs;
+  };
+
+  /**
+   * Message protocol encode.
+   *
+   * @param  {Number} id            message id
+   * @param  {Number} type          message type
+   * @param  {Number} compressRoute whether compress route
+   * @param  {Number|String} route  route code or route string
+   * @param  {Buffer} msg           message body bytes
+   * @return {Buffer}               encode result
+   */
+  Message.encode = function(id, type, compressRoute, route, msg){
+    // caculate message max length
+    var idBytes = msgHasId(type) ? caculateMsgIdBytes(id) : 0;
+    var msgLen = MSG_FLAG_BYTES + idBytes;
+
+    if(msgHasRoute(type)) {
+      if(compressRoute) {
+        if(typeof route !== 'number'){
+          throw new Error('error flag for number route!');
+        }
+        msgLen += MSG_ROUTE_CODE_BYTES;
+      } else {
+        msgLen += MSG_ROUTE_LEN_BYTES;
+        if(route) {
+          route = Protocol.strencode(route);
+          if(route.length>255) {
+            throw new Error('route maxlength is overflow');
+          }
+          msgLen += route.length;
+        }
+      }
+    }
+
+    if(msg) {
+      msgLen += msg.length;
+    }
+
+    var buffer = new ByteArray(msgLen);
+    var offset = 0;
+
+    // add flag
+    offset = encodeMsgFlag(type, compressRoute, buffer, offset);
+
+    // add message id
+    if(msgHasId(type)) {
+      offset = encodeMsgId(id, buffer, offset);
+    }
+
+    // add route
+    if(msgHasRoute(type)) {
+      offset = encodeMsgRoute(compressRoute, route, buffer, offset);
+    }
+
+    // add body
+    if(msg) {
+      offset = encodeMsgBody(msg, buffer, offset);
+    }
+
+    return buffer;
+  };
+
+  /**
+   * Message protocol decode.
+   *
+   * @param  {Buffer|Uint8Array} buffer message bytes
+   * @return {Object}            message object
+   */
+  Message.decode = function(buffer) {
+    var bytes =  new ByteArray(buffer);
+    var bytesLen = bytes.length || bytes.byteLength;
+    var offset = 0;
+    var id = 0;
+    var route = null;
+
+    // parse flag
+    var flag = bytes[offset++];
+    var compressRoute = flag & MSG_COMPRESS_ROUTE_MASK;
+    var type = (flag >> 1) & MSG_TYPE_MASK;
+
+    // parse id
+    if(msgHasId(type)) {
+      var m = parseInt(bytes[offset]);
+      var i = 0;
+      do{
+        var m = parseInt(bytes[offset]);
+        id = id + ((m & 0x7f) * Math.pow(2,(7*i)));
+        offset++;
+        i++;
+      }while(m >= 128);
+    }
+
+    // parse route
+    if(msgHasRoute(type)) {
+      if(compressRoute) {
+        route = (bytes[offset++]) << 8 | bytes[offset++];
+      } else {
+        var routeLen = bytes[offset++];
+        if(routeLen) {
+          route = new ByteArray(routeLen);
+          copyArray(route, 0, bytes, offset, routeLen);
+          route = Protocol.strdecode(route);
+        } else {
+          route = '';
+        }
+        offset += routeLen;
+      }
+    }
+
+    // parse body
+    var bodyLen = bytesLen - offset;
+    var body = new ByteArray(bodyLen);
+
+    copyArray(body, 0, bytes, offset, bodyLen);
+
+    return {'id': id, 'type': type, 'compressRoute': compressRoute,
+            'route': route, 'body': body};
+  };
+
+  var copyArray = function(dest, doffset, src, soffset, length) {
+    if('function' === typeof src.copy) {
+      // Buffer
+      src.copy(dest, doffset, soffset, soffset + length);
+    } else {
+      // Uint8Array
+      for(var index=0; index<length; index++){
+        dest[doffset++] = src[soffset++];
+      }
+    }
+  };
+
+  var msgHasId = function(type) {
+    return type === Message.TYPE_REQUEST || type === Message.TYPE_RESPONSE;
+  };
+
+  var msgHasRoute = function(type) {
+    return type === Message.TYPE_REQUEST || type === Message.TYPE_NOTIFY ||
+           type === Message.TYPE_PUSH;
+  };
+
+  var caculateMsgIdBytes = function(id) {
+    var len = 0;
+    do {
+      len += 1;
+      id >>= 7;
+    } while(id > 0);
+    return len;
+  };
+
+  var encodeMsgFlag = function(type, compressRoute, buffer, offset) {
+    if(type !== Message.TYPE_REQUEST && type !== Message.TYPE_NOTIFY &&
+       type !== Message.TYPE_RESPONSE && type !== Message.TYPE_PUSH) {
+      throw new Error('unkonw message type: ' + type);
+    }
+
+    buffer[offset] = (type << 1) | (compressRoute ? 1 : 0);
+
+    return offset + MSG_FLAG_BYTES;
+  };
+
+  var encodeMsgId = function(id, buffer, offset) {
+    do{
+      var tmp = id % 128;
+      var next = Math.floor(id/128);
+
+      if(next !== 0){
+        tmp = tmp + 128;
+      }
+      buffer[offset++] = tmp;
+
+      id = next;
+    } while(id !== 0);
+
+    return offset;
+  };
+
+  var encodeMsgRoute = function(compressRoute, route, buffer, offset) {
+    if (compressRoute) {
+      if(route > MSG_ROUTE_CODE_MAX){
+        throw new Error('route number is overflow');
+      }
+
+      buffer[offset++] = (route >> 8) & 0xff;
+      buffer[offset++] = route & 0xff;
+    } else {
+      if(route) {
+        buffer[offset++] = route.length & 0xff;
+        copyArray(buffer, offset, route, 0, route.length);
+        offset += route.length;
+      } else {
+        buffer[offset++] = 0;
+      }
+    }
+
+    return offset;
+  };
+
+  var encodeMsgBody = function(msg, buffer, offset) {
+    copyArray(buffer, offset, msg, 0, msg.length);
+    return offset + msg.length;
+  };
+
+  if(typeof(window) != "undefined") {
+    window.Protocol = Protocol;
+  }
+})(typeof(window)=="undefined" ? module.exports : (this.Protocol = {}),typeof(window)=="undefined"  ? Buffer : Uint8Array, this);

+ 0 - 0
public_original/swenv.js → public_original/scripts/swenv.js


+ 1 - 1
scripts/writeVariable.js

@@ -1,7 +1,7 @@
 const fs = require("fs");
 
 fs.writeFileSync(
-    "./public/swenv.js",
+    "./public/scripts/swenv.js",
     `
   const process = {
     env: {

+ 1 - 0
src/api/login.ts

@@ -27,6 +27,7 @@ export interface EntityTokenResp {
      * 用户名
      */
     user_name?: string;
+    gate: any;
 }
 
 export const loginApi = (data: loginParams) => {

+ 0 - 1
src/app/[locale]/(TabBar)/[[...share]]/@swiperWidget/page.tsx

@@ -17,7 +17,6 @@ const getBanners = React.cache(async () => {
 });
 const Page = async () => {
     const banners = await getBanners();
-
     if (!banners.length) return null;
 
     return <HomeSwiper banners={banners}></HomeSwiper>;

+ 3 - 2
src/app/[locale]/(TabBar)/[[...share]]/page.tsx

@@ -3,7 +3,6 @@ import { GroupType, PrizeTypes } from "@/api/home";
 import { server } from "@/utils/client";
 import React from "react";
 import HomeTabs from "./_home/HomeTabs";
-
 // const HomeTabs = () => import("./_home/HomeTabs");
 
 const TIME = 0;
@@ -15,6 +14,7 @@ const getGames = async () => {
             // next: { revalidate: TIME },
         })
         .then((res) => {
+            console.log(`🚀🚀🚀🚀🚀-> in page.tsx on 17`, res);
             if (res.code === 200) return res.data;
             return [];
         });
@@ -37,7 +37,8 @@ export default function Page(props: any) {
         const groupData = await getGames();
         setGroup(groupData);
     };
-    //const group = await getGames();
+    // const group = await getGames();
+    // console.log(`🚀🚀🚀🚀🚀-> in page.tsx on 40`, group);
     // const result = await getPrizeApi();
     if (!group?.length) return null;
     return (

+ 1 - 0
src/app/[locale]/(enter)/components/Form/index.tsx

@@ -217,6 +217,7 @@ const FormComponent: FC<Props> = (props) => {
             if (loginResult?.code === 200) {
                 eventLogin();
                 setCookies("Token", loginResult.data.token as string);
+                Local.setKey("wss", loginResult.data.gate);
                 // loginAction(loginResult.data.token)
                 const result = await userInfoApi();
                 if (result.code === 200) {

+ 32 - 1
src/app/[locale]/providers.tsx

@@ -21,12 +21,14 @@ import { motion } from "framer-motion";
 import { useEventPoint } from "@/hooks/useEventPoint";
 import { useActivityStore } from "@/stores/useActivityStore";
 import { useGlobalNoticeStore } from "@/stores/useGlobalNoticeStore";
+import { getToken as getUserToken } from "@/utils/Cookies";
+
 import { PollingState, usePollingStore } from "@/stores/usePollingStore";
 import { useSuspensionStore } from "@/stores/useSuspensionStore";
 import { useVipStore } from "@/stores/useVipStore";
 import { useWalletStore } from "@/stores/useWalletStore";
-import styles from "./style.module.scss";
 
+import styles from "./style.module.scss";
 export interface ProvidersProps {
     children: ReactNode;
     themeProps?: Omit<ThemeProviderProps, "children">;
@@ -316,6 +318,33 @@ const InitAdvertise = () => {
     );
 };
 
+const WssClient = () => {
+    const [token, setToken] = useState<string | undefined>(undefined);
+    const setWallet = useWalletStore((state) => state.setWallet);
+    useEffect(() => {
+        setToken(() => getUserToken());
+
+        const wss = Local.getKey("wss");
+        if (wss && window.pomelo) {
+            window.pomelo.init({ host: wss?.address, port: wss.port, path: "/" }, function () {
+                console.log("connected!");
+
+                window.pomelo.on("onUserInfo", (data) => {
+                    setWallet(data);
+                });
+                // request login
+                window.pomelo.request("gate.user.login", { token });
+            });
+        }
+    }, [token]);
+    return (
+        <>
+            <Script src={"/scripts/protocol.js"}></Script>
+            <Script src={"/scripts/pomelo-client-json.js"}></Script>
+        </>
+    );
+};
+
 export default function SidebarLayout({ children, themeProps }: ProvidersProps) {
     const { isCollapse, setCollapse } = useSystemStore((state) => ({
         isCollapse: state.isCollapse,
@@ -361,6 +390,8 @@ export default function SidebarLayout({ children, themeProps }: ProvidersProps)
                 <StopServiceClient />
                 {/*轮询*/}
                 <PollingClient />
+                {/*长链接*/}
+                {/*<WssClient />*/}
                 <section className={clsx(isShowBg && styles.homePage, "relative h-[100%]")}>
                     {children}
                 </section>

+ 1 - 1
src/components/HeaderBack/index.tsx

@@ -6,7 +6,6 @@ import clsx from "clsx";
 import { useTranslations } from "next-intl";
 import { FC, PropsWithChildren, ReactNode, useEffect, useState } from "react";
 import styles from "./style.module.scss";
-
 // import { getToken } from "@/utils/Cookies";
 
 /**
@@ -67,6 +66,7 @@ const HeaderBack: FC<PropsWithChildren<HeaderBackProps>> = ({
 
     const router = useRouter();
     const goPage = async (path = "") => {
+        // clearCache();
         if (path) {
             // await clearCache();
             router.replace("/");

+ 1 - 0
src/utils/storage/index.ts

@@ -8,6 +8,7 @@ interface StorageKey {
     ban_pop_type_1: string;
     pop_type_2: string;
     pop_type_3: string;
+    wss: { node: string; address: string; port: number };
 }
 type Key = Extract<keyof StorageKey, string>;
 class CustomStorage {