feat(rn): 添加服务器时增加基本信息的获取

pull/90/head
moonrailgun 2 years ago
parent e92d921164
commit c972eb8937

@ -13,6 +13,7 @@
"dependencies": {
"@notifee/react-native": "^7.4.0",
"immer": "^9.0.19",
"lodash": "^4.17.21",
"mini-star": "^2.0.8",
"react": "18.2.0",
"react-native": "0.71.2",
@ -20,6 +21,7 @@
"react-native-reanimated": "^2.14.4",
"react-native-ui-lib": "^6.29.1",
"react-native-webview": "^11.26.1",
"url-regex": "^5.0.0",
"zustand": "^4.3.2"
},
"devDependencies": {
@ -29,6 +31,7 @@
"@react-native-community/eslint-config": "^3.2.0",
"@tsconfig/react-native": "^2.0.2",
"@types/jest": "^29.2.1",
"@types/lodash": "^4.14.191",
"@types/react": "^18.0.24",
"@types/react-test-renderer": "^18.0.0",
"babel-jest": "^29.2.1",

@ -1,14 +1,16 @@
import React, { useState } from 'react';
import { ScrollView, StyleSheet, TextInput } from 'react-native';
import { Alert, ScrollView, StyleSheet, TextInput } from 'react-native';
import { ServerCard } from './components/ServerCard';
import { useServerStore } from './store/server';
import Dialog from 'react-native-ui-lib/dialog';
import { Button, PanningProvider, Text, View } from 'react-native-ui-lib';
import { isValidUrl } from './lib/utils';
export const Entry: React.FC = React.memo(() => {
const { serverList, selectServer, addServer } = useServerStore();
const [dialogVisible, setDialogVisible] = useState(false);
const [serverUrl, setServerUrl] = useState('');
const [loading, setLoading] = useState(false);
return (
<ScrollView style={styles.root}>
@ -19,6 +21,7 @@ export const Entry: React.FC = React.memo(() => {
style={styles.item}
name={serverInfo.name ?? serverInfo.url}
url={serverInfo.url}
version={serverInfo.version}
onPress={() => selectServer(serverInfo)}
/>
);
@ -43,9 +46,24 @@ export const Entry: React.FC = React.memo(() => {
<Button
label={'确认'}
onPress={() => {
addServer(serverUrl);
setDialogVisible(false);
disabled={loading}
onPress={async () => {
if (!isValidUrl(serverUrl)) {
Alert.alert('输入不是一个有效的url');
return;
}
setLoading(true);
try {
await addServer(serverUrl);
setDialogVisible(false);
} catch (e) {
Alert.alert(
'添加服务器失败, 可能输入的地址不是一个Tailchat服务地址'
);
}
setLoading(false);
}}
/>
</View>

@ -11,6 +11,7 @@ interface ServerCardProps {
style?: StyleProp<ViewStyle>;
name: string;
url?: string;
version?: string;
onPress?: () => void;
}
export const ServerCard: React.FC<ServerCardProps> = React.memo((props) => {
@ -22,6 +23,10 @@ export const ServerCard: React.FC<ServerCardProps> = React.memo((props) => {
<Text style={styles.name}>{props.name}</Text>
{props.url && <Text style={styles.url}>{props.url}</Text>}
{props.version && (
<Text style={styles.version}>version: {props.version}</Text>
)}
</TouchableOpacity>
);
});
@ -41,6 +46,11 @@ const styles = StyleSheet.create({
fontSize: 16,
textAlign: 'center',
},
version: {
color: '#999',
textAlign: 'center',
fontSize: 10,
},
url: {
color: '#999',
textAlign: 'center',

@ -0,0 +1,35 @@
import urlRegex from 'url-regex';
import _flatten from 'lodash/flatten';
/**
* url
*/
export function isValidUrl(str: unknown): str is string {
return typeof str === 'string' && urlRegex({ exact: true }).test(str);
}
export function normalize(path: string) {
const components: string[] = [];
for (const component of `${path}`.split(/\/+/g)) {
if (component === '.') {
} else if (component === '..') {
components.pop();
} else {
components.push(component);
}
}
let normalized = (
(path.startsWith('/') ? '/' : '') + components.join('/')
).replace(/\/\/+/g, '/');
return normalized || '.';
}
export function urlResolve(...str: string[]) {
const flatten = _flatten(str).reduce((previous, current) => {
if (/^\//.test(current)) {
return current;
}
return `${previous}/${current}`;
});
return normalize(flatten);
}

@ -1,5 +1,6 @@
import { create } from 'zustand';
import { immer } from 'zustand/middleware/immer';
import { urlResolve } from '../lib/utils';
interface ServerInfo {
name?: string;
@ -10,7 +11,7 @@ interface ServerInfo {
interface ServerStoreState {
selectedServerInfo: ServerInfo | null;
serverList: ServerInfo[];
addServer: (url: string) => void;
addServer: (url: string) => Promise<void>;
selectServer: (serverInfo: ServerInfo) => void;
}
@ -25,12 +26,32 @@ export const useServerStore = create<ServerStoreState>()(
immer((set) => ({
serverList: defaultServerList,
selectedServerInfo: null,
addServer: (url: string) => {
set((state) => {
state.serverList.push({
url,
addServer: async (url: string) => {
try {
// 获取 Tailchat 客户端配置
const res = await fetch(urlResolve(url, './tailchat.manifest'));
const clientConfig = await res.json();
const { version, serviceUrl } = clientConfig;
console.log('获取Tailchat客户端配置成功', clientConfig);
// 获取 Tailchat 服务端配置
const res2 = await fetch(
urlResolve(serviceUrl ?? url, './api/config/client')
);
const serviceConfig = (await res2.json()).data;
console.log('获取Tailchat服务端配置成功', serviceConfig);
set((state) => {
state.serverList.push({
name: serviceConfig.appName ?? 'Tailchat',
url,
version,
});
});
});
} catch (err) {
console.error('获取服务器配置失败:', err);
throw err;
}
},
selectServer: (serverInfo: ServerInfo) => {
set({

@ -1834,6 +1834,11 @@
resolved "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3"
integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==
"@types/lodash@^4.14.191":
version "4.14.191"
resolved "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.191.tgz#09511e7f7cba275acd8b419ddac8da9a6a79e2fa"
integrity sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==
"@types/node@*":
version "18.13.0"
resolved "https://registry.npmmirror.com/@types/node/-/node-18.13.0.tgz#0400d1e6ce87e9d3032c19eb6c58205b0d3f7850"
@ -4358,6 +4363,11 @@ invariant@*, invariant@2.2.4, invariant@^2.2.4:
dependencies:
loose-envify "^1.0.0"
ip-regex@^4.1.0:
version "4.3.0"
resolved "https://registry.npmmirror.com/ip-regex/-/ip-regex-4.3.0.tgz#687275ab0f57fa76978ff8f4dddc8a23d5990db5"
integrity sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==
ip@^1.1.5:
version "1.1.8"
resolved "https://registry.npmmirror.com/ip/-/ip-1.1.8.tgz#ae05948f6b075435ed3307acce04629da8cdbf48"
@ -7872,6 +7882,11 @@ tinycolor2@^1.4.2:
resolved "https://registry.npmmirror.com/tinycolor2/-/tinycolor2-1.6.0.tgz#f98007460169b0263b97072c5ae92484ce02d09e"
integrity sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==
tlds@^1.203.0:
version "1.236.0"
resolved "https://registry.npmmirror.com/tlds/-/tlds-1.236.0.tgz#a118eebe33261c577e3a3025144faeabb7dd813c"
integrity sha512-oP2PZ3KeGlgpHgsEfrtva3/K9kzsJUNliQSbCfrJ7JMCWFoCdtG+9YMq/g2AnADQ1v5tVlbtvKJZ4KLpy/P6MA==
tmp@^0.0.33:
version "0.0.33"
resolved "https://registry.npmmirror.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
@ -8111,6 +8126,14 @@ url-parse@^1.2.0:
querystringify "^2.1.1"
requires-port "^1.0.0"
url-regex@^5.0.0:
version "5.0.0"
resolved "https://registry.npmmirror.com/url-regex/-/url-regex-5.0.0.tgz#8f5456ab83d898d18b2f91753a702649b873273a"
integrity sha512-O08GjTiAFNsSlrUWfqF1jH0H1W3m35ZyadHrGv5krdnmPPoxP27oDTqux/579PtaroiSGm5yma6KT1mHFH6Y/g==
dependencies:
ip-regex "^4.1.0"
tlds "^1.203.0"
use-memo-one@^1.1.1:
version "1.1.3"
resolved "https://registry.npmmirror.com/use-memo-one/-/use-memo-one-1.1.3.tgz#2fd2e43a2169eabc7496960ace8c79efef975e99"

Loading…
Cancel
Save