Ver Fonte

20230304: updated webpack.config.js for websocket, os library

mkbeefcake há 1 ano atrás
pai
commit
34d35f5bb1
8 ficheiros alterados com 865 adições e 16 exclusões
  1. 8 0
      package.json
  2. 2 2
      src/config.ts
  3. 1 1
      src/index.tsx
  4. 183 0
      src/providers/AccountProvider.tsx
  5. 1 1
      src/providers/Providers.tsx
  6. 1 1
      tsconfig.json
  7. 15 2
      webpack.config.js
  8. 654 9
      yarn.lock

+ 8 - 0
package.json

@@ -10,6 +10,12 @@
     "@material-ui/data-grid": "^4.0.0-alpha.37",
     "@material-ui/icons": "^4.11.2",
     "@material-ui/lab": "^4.0.0-alpha.60",
+    "@polkadot/api": "^9.14.2",
+    "@polkadot/extension-dapp": "^0.44.9",
+    "@polkadot/keyring": "^10.4.2",
+    "@polkadot/react-identicon": "^2.12.1",
+    "@polkadot/types": "^9.14.2",
+    "@polkadot/ui-keyring": "^2.12.1",
     "axios": "^0.21.1",
     "babel-loader": "^9.1.2",
     "bootstrap": "^4.5.3",
@@ -18,6 +24,7 @@
     "htmr": "^0.9.2",
     "i18next": "^20.4.0",
     "i18next-browser-languagedetector": "^6.1.2",
+    "injectweb3-connect": "^1.2.7",
     "interactjs": "^1.10.2",
     "less": "^4.1.3",
     "less-loader": "^11.1.0",
@@ -96,6 +103,7 @@
     "file-loader": "^6.2.0",
     "graphql": "^16.6.0",
     "html-webpack-plugin": "^5.5.0",
+    "node-polyfill-webpack-plugin": "^2.0.1",
     "path-browserify": "^1.0.1",
     "raw-loader": "^4.0.2",
     "stream-browserify": "^3.0.0",

+ 2 - 2
src/config.ts

@@ -1,7 +1,7 @@
 export const historyDepth = 336;
 export const domain = "https://pioneer.joystreamstats.live";
-//export const wsLocation = "wss://joystreamstats.live:9945";
-export const wsLocation = "wss://rpc.joystream.org:9944";
+export const wsLocation = "wss://dev.joystreamstats.live:8080";
+//export const wsLocation = "wss://rpc.joystream.org:9944";
 export const apiLocation = "https://api.joystreamstats.live/api"
 export const socketLocation = "/socket.io"
 export const hydraLocation = "https://hydra.joystream.org/graphql"

+ 1 - 1
src/index.tsx

@@ -3,7 +3,7 @@ import ReactDOM from "react-dom";
 import { BrowserRouter as Router } from "react-router-dom";
 import "./index.css";
 import App from "./App";
-import Providers from "./Providers";
+import Providers from "./providers/Providers";
 
 import "./i18n";
 // <Router>

+ 183 - 0
src/providers/AccountProvider.tsx

@@ -0,0 +1,183 @@
+import { InjectedAccountWithMeta } from '@polkadot/extension-inject/types'
+import { Keyring } from '@polkadot/ui-keyring'
+import { decodeAddress, encodeAddress } from '@polkadot/util-crypto'
+import { getWalletBySource, Wallet } from 'injectweb3-connect'
+import React, { ReactNode, useEffect, useState } from 'react'
+import { debounceTime, filter, skip } from 'rxjs/operators'
+
+import { useKeyring } from '@/common/hooks/useKeyring'
+import { useLocalStorage } from '@/common/hooks/useLocalStorage'
+import { useObservable } from '@/common/hooks/useObservable'
+
+import { Account } from '../../types'
+
+import { AccountsContext } from './context'
+
+type ExtensionError = 'NO_EXTENSION' | 'APP_REJECTED'
+
+export interface UseAccounts {
+  allAccounts: Account[]
+  hasAccounts: boolean
+  isLoading: boolean
+  error?: ExtensionError
+  wallet?: Wallet
+  setWallet?: (wallet: Wallet | undefined) => void
+}
+
+const JOYSTREAM_SS58_PREFIX = 126
+
+interface Props {
+  children: ReactNode
+}
+
+function isKeyringLoaded(keyring: Keyring) {
+  try {
+    return !!keyring.keyring
+  } catch {
+    return false
+  }
+}
+
+const loadKeysFromExtension = async (keyring: Keyring, wallet: Wallet) => {
+  await wallet.enable('Pioneer')
+
+  const injectedAccounts = await wallet.getAccounts()
+
+  if (!isKeyringLoaded(keyring)) {
+    keyring.loadAll({ isDevelopment: false }, injectedAccounts.map(wallet.walletAccountToInjectedAccountWithMeta))
+  }
+
+  await wallet.subscribeAccounts((accounts) => {
+    const current = keyring.getAccounts()
+
+    const addresses = accounts?.map(({ address }) => address) ?? []
+
+    current.forEach(({ address }) => {
+      if (!addresses.includes(address)) {
+        keyring.forgetAccount(address)
+      }
+    })
+
+    accounts
+      ?.map(wallet.walletAccountToInjectedAccountWithMeta)
+      .forEach((injected: InjectedAccountWithMeta) => keyring.addExternal(injected.address, injected.meta))
+  })
+}
+
+// Extensions is not always ready on application load, hence the check
+const onExtensionLoaded =
+  (onSuccess: (foundWallets: string[]) => void, onFail: () => void, recentWallet?: string) => () => {
+    const interval = 20
+    const timeout = 1000
+    let timeElapsed = 0
+
+    const intervalId = setInterval(() => {
+      const extensionsKeys = Object.keys((window as any)?.injectedWeb3 ?? {})
+      if (extensionsKeys.length) {
+        if (!recentWallet) {
+          clearInterval(intervalId)
+          onSuccess(extensionsKeys)
+        } else if (extensionsKeys.includes(recentWallet)) {
+          // some wallets load slower which will cause error when trying to preload them hence the check
+          clearInterval(intervalId)
+          onSuccess(extensionsKeys)
+        } else if (timeElapsed >= timeout) {
+          // if wallet in storage was disabled we don't want to wait for it too long
+          clearInterval(intervalId)
+          onSuccess(extensionsKeys)
+        }
+        timeElapsed += interval
+      } else {
+        timeElapsed += interval
+        if (timeElapsed >= timeout) {
+          clearInterval(intervalId)
+          onFail()
+        }
+      }
+    }, interval)
+
+    return () => clearInterval(intervalId)
+  }
+
+export const AccountsContextProvider = (props: Props) => {
+  const keyring = useKeyring()
+  const [isExtensionLoaded, setIsExtensionLoaded] = useState(false)
+  const [selectedWallet, setSelectedWallet] = useState<Wallet>()
+  const [extensionError, setExtensionError] = useState<ExtensionError>()
+  const [recentWallet, setRecentWallet] = useLocalStorage<string | undefined>('recentWallet')
+
+  useEffect(
+    onExtensionLoaded(
+      (foundWallets) => {
+        setIsExtensionLoaded(true)
+        if (recentWallet && foundWallets.includes(recentWallet)) {
+          const possibleWallet = getWalletBySource(recentWallet)
+          setSelectedWallet(possibleWallet)
+        }
+      },
+      () => setExtensionError('NO_EXTENSION'),
+      recentWallet
+    ),
+    []
+  )
+
+  useEffect(() => {
+    if (!isExtensionLoaded || !selectedWallet) {
+      return
+    }
+
+    setExtensionError(undefined)
+    loadKeysFromExtension(keyring, selectedWallet)
+      .then(() => {
+        setRecentWallet(selectedWallet.extensionName)
+      })
+      .catch((error: Error) => {
+        setSelectedWallet(undefined)
+
+        if (error?.message.includes('not allowed to interact') || error?.message.includes('Rejected')) {
+          setExtensionError('APP_REJECTED')
+        }
+      })
+  }, [isExtensionLoaded, selectedWallet])
+
+  const accounts = useObservable(
+    () =>
+      keyring.accounts.subject.asObservable().pipe(
+        debounceTime(20),
+        filter((accounts) => !!accounts),
+        skip(1)
+      ),
+    [keyring]
+  )
+  const allAccounts: Account[] = []
+
+  if (accounts && selectedWallet) {
+    allAccounts.push(
+      ...Object.values(accounts).map((account) => {
+        const publicKey = decodeAddress(account.json.address)
+        return {
+          address: encodeAddress(publicKey, JOYSTREAM_SS58_PREFIX),
+          name: account.json.meta.name,
+          source: account.json.meta.source as string,
+        }
+      })
+    )
+  }
+
+  const hasAccounts = allAccounts.length !== 0
+
+  const value: UseAccounts = {
+    allAccounts,
+    hasAccounts,
+    isLoading: !isExtensionLoaded || !accounts,
+    setWallet: setSelectedWallet,
+    wallet: selectedWallet,
+    error: extensionError,
+  }
+
+  if (extensionError || !selectedWallet?.extension) {
+    value.isLoading = false
+  }
+
+  return <AccountsContext.Provider value={value}>{props.children}</AccountsContext.Provider>
+}

+ 1 - 1
src/Providers.tsx → src/providers/Providers.tsx

@@ -1,6 +1,6 @@
 import { ApolloClient, ApolloProvider, InMemoryCache } from '@apollo/client';
 import React from 'react';
-import { queryNode } from './config';
+import { queryNode } from '../config';
 
 const client = new ApolloClient({
   // uri: import.meta.env.VITE_QN_URL,

+ 1 - 1
tsconfig.json

@@ -4,7 +4,7 @@
   },
   "include": [
       "src/*"
-  ],
+, "src/providers/Providers.tsx"  ],
   "compilerOptions": {
       "target": "es2020",
       "lib": ["ES2020", "DOM"],

+ 15 - 2
webpack.config.js

@@ -2,6 +2,7 @@ const path = require('path');
 const webpack = require('webpack')
 const HtmlWebpackPlugin = require('html-webpack-plugin');
 const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
+const NodePolyfillPlugin = require("node-polyfill-webpack-plugin");
 
 const { DEV, DEBUG } = process.env;
 
@@ -15,7 +16,18 @@ module.exports = {
         filename: 'bundle.js'
     },
     devServer: {
-        port: 8080
+        port: 8080,
+        client: {
+          logging: 'error',
+          progress: true,
+          overlay: true,
+          webSocketURL: {
+            hostname: 'dev.joystreamstats.live',
+            pathname: '/ws',
+            port: 443,
+            protocol: 'wss'
+          }
+        }
     },
     module: {
         rules: [
@@ -108,6 +120,7 @@ module.exports = {
         Buffer: ['buffer', 'Buffer'],
         process: 'process/browser.js',
         "React": "react",
-      }),      
+      }),
+      new NodePolyfillPlugin()
     ]
 }

Diff do ficheiro suprimidas por serem muito extensas
+ 654 - 9
yarn.lock


Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff