Try out new api services

This commit is contained in:
Zhiyuan Zheng 2021-12-06 21:25:09 +01:00
parent 3d481624ad
commit 6c6dc0ce6a
10 changed files with 82 additions and 132 deletions

View File

@ -72,6 +72,7 @@
"react-i18next": "11.14.3", "react-i18next": "11.14.3",
"react-native": "0.66.3", "react-native": "0.66.3",
"react-native-animated-spinkit": "1.5.2", "react-native-animated-spinkit": "1.5.2",
"react-native-base64": "^0.2.1",
"react-native-blurhash": "1.1.5", "react-native-blurhash": "1.1.5",
"react-native-fast-image": "8.5.11", "react-native-fast-image": "8.5.11",
"react-native-feather": "1.1.2", "react-native-feather": "1.1.2",
@ -103,6 +104,7 @@
"@types/react": "17.0.37", "@types/react": "17.0.37",
"@types/react-dom": "17.0.11", "@types/react-dom": "17.0.11",
"@types/react-native": "0.66.6", "@types/react-native": "0.66.6",
"@types/react-native-base64": "^0.2.0",
"@types/react-redux": "7.1.20", "@types/react-redux": "7.1.20",
"@types/react-timeago": "4.1.3", "@types/react-timeago": "4.1.3",
"@types/valid-url": "1.0.3", "@types/valid-url": "1.0.3",

View File

@ -6,8 +6,7 @@ import * as Sentry from 'sentry-expo'
const ctx = new chalk.Instance({ level: 3 }) const ctx = new chalk.Instance({ level: 3 })
export type Params = { export type Params = {
service: 'push' | 'translate' method: 'get' | 'post' | 'put' | 'delete'
method: 'get' | 'post'
url: string url: string
params?: { params?: {
[key: string]: string | number | boolean | string[] | number[] | boolean[] [key: string]: string | number | boolean | string[] | number[] | boolean[]
@ -17,10 +16,9 @@ export type Params = {
sentry?: boolean sentry?: boolean
} }
const DOMAIN = __DEV__ ? 'testapi.tooot.app' : 'api.tooot.app' export const TOOOT_API_DOMAIN = __DEV__ ? 'testapi.tooot.app' : 'testapi.tooot.app'
const apiTooot = async <T = unknown>({ const apiTooot = async <T = unknown>({
service,
method, method,
url, url,
params, params,
@ -28,8 +26,6 @@ const apiTooot = async <T = unknown>({
body, body,
sentry = false sentry = false
}: Params): Promise<{ body: T }> => { }: Params): Promise<{ body: T }> => {
const key = Constants.manifest?.extra?.toootApiKey
console.log( console.log(
ctx.bgGreen.bold(' API tooot ') + ctx.bgGreen.bold(' API tooot ') +
' ' + ' ' +
@ -43,11 +39,10 @@ const apiTooot = async <T = unknown>({
return axios({ return axios({
timeout: method === 'post' ? 1000 * 60 : 1000 * 15, timeout: method === 'post' ? 1000 * 60 : 1000 * 15,
method, method,
baseURL: `https://${DOMAIN}/`, baseURL: `https://${TOOOT_API_DOMAIN}/`,
url: `${service}/${url}`, url: `${url}`,
params, params,
headers: { headers: {
...(key && { 'x-tooot-key': key }),
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'User-Agent': `tooot/${Constants.manifest?.version}`, 'User-Agent': `tooot/${Constants.manifest?.version}`,
Accept: '*/*', Accept: '*/*',

View File

@ -76,7 +76,7 @@ const pushUseConnect = ({ mode, t, instances, dispatch }: Params) => {
const pushEnabled = instances.filter(instance => instance.push.global.value) const pushEnabled = instances.filter(instance => instance.push.global.value)
if (pushEnabled.length) { if (pushEnabled.length) {
connect() // connect()
} }
}, [instances]) }, [instances])
} }

View File

@ -36,9 +36,9 @@ const queryFunction = async ({ queryKey }: { queryKey: QueryKeyTranslate }) => {
const res = await apiTooot<Translations>({ const res = await apiTooot<Translations>({
method: 'get', method: 'get',
service: 'translate', url: '/translate',
url: `source/${uriEncoded}/target/${target}`, headers: { original },
headers: { original } body: { source, target, text }
}) })
haptics('Light') haptics('Light')
return res.body return res.body

View File

@ -1,53 +1,33 @@
import apiInstance from '@api/instance' import apiInstance from '@api/instance'
import apiTooot from '@api/tooot' import apiTooot, { TOOOT_API_DOMAIN } from '@api/tooot'
import i18n from '@root/i18n/i18n' import i18n from '@root/i18n/i18n'
import { RootState } from '@root/store' import { RootState } from '@root/store'
import { getInstance, Instance } from '@utils/slices/instancesSlice' import { getInstance, Instance } from '@utils/slices/instancesSlice'
import * as Notifications from 'expo-notifications' import * as Notifications from 'expo-notifications'
import * as Random from 'expo-random'
import { Platform } from 'react-native' import { Platform } from 'react-native'
import base64 from 'react-native-base64'
import androidDefaults from './androidDefaults' import androidDefaults from './androidDefaults'
const register1 = async ({ const subscribe = async ({
expoToken, expoToken,
instanceUrl, instanceUrl,
accountId, accountId,
accountFull accountFull,
serverKey,
auth
}: { }: {
expoToken: string expoToken: string
instanceUrl: string instanceUrl: string
accountId: Mastodon.Account['id'] accountId: Mastodon.Account['id']
accountFull: string accountFull: string
}) => { serverKey: string
return apiTooot<{ auth: string | null
endpoint: string
keys: { public: string; private: string; auth: string }
}>({
method: 'post',
service: 'push',
url: 'register1',
body: { expoToken, instanceUrl, accountId, accountFull },
sentry: true
})
}
const register2 = async ({
expoToken,
serverKey,
instanceUrl,
accountId,
removeKeys
}: {
expoToken: string
serverKey: Mastodon.PushSubscription['server_key']
instanceUrl: string
accountId: Mastodon.Account['id']
removeKeys: boolean
}) => { }) => {
return apiTooot({ return apiTooot({
method: 'post', method: 'post',
service: 'push', url: `/push/subscribe/${expoToken}/${instanceUrl}/${accountId}`,
url: 'register2', body: { accountFull, serverKey, auth },
body: { expoToken, instanceUrl, accountId, serverKey, removeKeys },
sentry: true sentry: true
}) })
} }
@ -55,7 +35,7 @@ const register2 = async ({
const pushRegister = async ( const pushRegister = async (
state: RootState, state: RootState,
expoToken: string expoToken: string
): Promise<Instance['push']['keys']> => { ): Promise<Instance['push']['keys']['auth']> => {
const instance = getInstance(state) const instance = getInstance(state)
const instanceUrl = instance?.url const instanceUrl = instance?.url
const instanceUri = instance?.uri const instanceUri = instance?.uri
@ -68,18 +48,18 @@ const pushRegister = async (
const accountId = instanceAccount.id const accountId = instanceAccount.id
const accountFull = `@${instanceAccount.acct}@${instanceUri}` const accountFull = `@${instanceAccount.acct}@${instanceUri}`
const serverRes = await register1({
expoToken, const endpoint = `https://${TOOOT_API_DOMAIN}/push/send/${expoToken}/${instanceUrl}/${accountId}`
instanceUrl, const auth = base64.encodeFromByteArray(Random.getRandomBytes(16))
accountId,
accountFull
})
const alerts = instancePush.alerts const alerts = instancePush.alerts
const formData = new FormData() const formData = new FormData()
formData.append('subscription[endpoint]', serverRes.body.endpoint) formData.append('subscription[endpoint]', endpoint)
formData.append('subscription[keys][p256dh]', serverRes.body.keys.public) formData.append(
formData.append('subscription[keys][auth]', serverRes.body.keys.auth) 'subscription[keys][p256dh]',
'BO3P7Fe/FxPNijeXayVYViCoLicnnACc+a55wzcS0qIjYU++dtAl2XltgEfU5qPuXrFg5rnxBzbwQG4cAmdNLK4='
)
formData.append('subscription[keys][auth]', auth)
Object.keys(alerts).map(key => Object.keys(alerts).map(key =>
// @ts-ignore // @ts-ignore
formData.append(`data[alerts][${key}]`, alerts[key].value.toString()) formData.append(`data[alerts][${key}]`, alerts[key].value.toString())
@ -91,12 +71,13 @@ const pushRegister = async (
body: formData body: formData
}) })
await register2({ await subscribe({
expoToken, expoToken,
serverKey: res.body.server_key,
instanceUrl, instanceUrl,
accountId, accountId,
removeKeys: instancePush.decode.value === false accountFull,
serverKey: res.body.server_key,
auth
}) })
if (Platform.OS === 'android') { if (Platform.OS === 'android') {
@ -142,7 +123,7 @@ const pushRegister = async (
}) })
} }
return Promise.resolve(serverRes.body.keys) return Promise.resolve(auth)
} }
export default pushRegister export default pushRegister

View File

@ -20,14 +20,8 @@ const pushUnregister = async (state: RootState, expoToken: string) => {
}) })
await apiTooot<{ endpoint: string; publicKey: string; auth: string }>({ await apiTooot<{ endpoint: string; publicKey: string; auth: string }>({
method: 'post', method: 'delete',
service: 'push', url: `/push/unsubscribe/${expoToken}/${instance.url}/${instance.account.id}`,
url: 'unregister',
body: {
expoToken,
instanceUrl: instance.url,
accountId: instance.account.id
},
sentry: true sentry: true
}) })

View File

@ -10,7 +10,7 @@ export const updateInstancePush = createAsyncThunk(
async ( async (
disable: boolean, disable: boolean,
{ getState } { getState }
): Promise<Instance['push']['keys'] | undefined> => { ): Promise<Instance['push']['keys']['auth'] | undefined> => {
const state = getState() as RootState const state = getState() as RootState
const expoToken = ( const expoToken = (
await Notifications.getExpoPushTokenAsync({ await Notifications.getExpoPushTokenAsync({

View File

@ -26,14 +26,10 @@ export const updateInstancePushDecode = createAsyncThunk(
).data ).data
await apiTooot({ await apiTooot({
method: 'post', method: 'put',
service: 'push', url: `/push/update-decode/${expoToken}/${instance.url}/${instance.account.id}`,
url: 'update-decode',
body: { body: {
expoToken, auth: disable ? null : instance.push.keys.auth
instanceUrl: instance.url,
accountId: instance.account.id,
...(disable && { keys: instance.push.keys })
}, },
sentry: true sentry: true
}) })

View File

@ -39,65 +39,37 @@ export type Instance = {
poll: boolean poll: boolean
follow_request: boolean follow_request: boolean
} }
push: push: {
| { global: { loading: boolean; value: boolean }
global: { loading: boolean; value: boolean } decode: { loading: boolean; value: boolean }
decode: { loading: boolean; value: true } alerts: {
alerts: { follow: {
follow: { loading: boolean
loading: boolean value: Mastodon.PushSubscription['alerts']['follow']
value: Mastodon.PushSubscription['alerts']['follow']
}
favourite: {
loading: boolean
value: Mastodon.PushSubscription['alerts']['favourite']
}
reblog: {
loading: boolean
value: Mastodon.PushSubscription['alerts']['reblog']
}
mention: {
loading: boolean
value: Mastodon.PushSubscription['alerts']['mention']
}
poll: {
loading: boolean
value: Mastodon.PushSubscription['alerts']['poll']
}
}
keys: {
auth: string
public: string
private: string
}
} }
| { favourite: {
global: { loading: boolean; value: boolean } loading: boolean
decode: { loading: boolean; value: false } value: Mastodon.PushSubscription['alerts']['favourite']
alerts: {
follow: {
loading: boolean
value: Mastodon.PushSubscription['alerts']['follow']
}
favourite: {
loading: boolean
value: Mastodon.PushSubscription['alerts']['favourite']
}
reblog: {
loading: boolean
value: Mastodon.PushSubscription['alerts']['reblog']
}
mention: {
loading: boolean
value: Mastodon.PushSubscription['alerts']['mention']
}
poll: {
loading: boolean
value: Mastodon.PushSubscription['alerts']['poll']
}
}
keys: undefined
} }
reblog: {
loading: boolean
value: Mastodon.PushSubscription['alerts']['reblog']
}
mention: {
loading: boolean
value: Mastodon.PushSubscription['alerts']['mention']
}
poll: {
loading: boolean
value: Mastodon.PushSubscription['alerts']['poll']
}
}
keys: {
auth?: string
public?: string // legacy
private?: string // legacy
}
}
drafts: ComposeStateDraft[] drafts: ComposeStateDraft[]
} }
@ -273,7 +245,7 @@ const instancesSlice = createSlice({
const activeIndex = findInstanceActive(state.instances) const activeIndex = findInstanceActive(state.instances)
state.instances[activeIndex].push.global.loading = false state.instances[activeIndex].push.global.loading = false
state.instances[activeIndex].push.global.value = action.meta.arg state.instances[activeIndex].push.global.value = action.meta.arg
state.instances[activeIndex].push.keys = action.payload state.instances[activeIndex].push.keys = { auth: action.payload }
}) })
.addCase(updateInstancePush.rejected, state => { .addCase(updateInstancePush.rejected, state => {
const activeIndex = findInstanceActive(state.instances) const activeIndex = findInstanceActive(state.instances)

View File

@ -2190,6 +2190,11 @@
dependencies: dependencies:
"@types/react" "*" "@types/react" "*"
"@types/react-native-base64@^0.2.0":
version "0.2.0"
resolved "https://registry.yarnpkg.com/@types/react-native-base64/-/react-native-base64-0.2.0.tgz#c934e7c3cd549d4613bbfa7929a6845ab07a20af"
integrity sha512-5kUtS7Kf8Xl4zEwbqLITEuQReQTby4UOGfnsEeBFJEVmUfT+ygOv/Qmv0v6El0iV1eDhXS+/0i7CGR9d3/nRSA==
"@types/react-native@0.66.6": "@types/react-native@0.66.6":
version "0.66.6" version "0.66.6"
resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.66.6.tgz#08f5b93cca9a50b7d19f353ff2a1ebe1a7c24a79" resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.66.6.tgz#08f5b93cca9a50b7d19f353ff2a1ebe1a7c24a79"
@ -6310,6 +6315,11 @@ react-native-animated-spinkit@1.5.2:
resolved "https://registry.yarnpkg.com/react-native-animated-spinkit/-/react-native-animated-spinkit-1.5.2.tgz#b1c00ecbadf48634273e6a843f8dfbcb7c006186" resolved "https://registry.yarnpkg.com/react-native-animated-spinkit/-/react-native-animated-spinkit-1.5.2.tgz#b1c00ecbadf48634273e6a843f8dfbcb7c006186"
integrity sha512-YCQGR3HzEQvyaAnepiyf/hv88Sta3UIZ2CFZPtFqwu+VbFJfMgjJZniOx4157TuR5AAYajEJP9Fgy+JLIU3jzQ== integrity sha512-YCQGR3HzEQvyaAnepiyf/hv88Sta3UIZ2CFZPtFqwu+VbFJfMgjJZniOx4157TuR5AAYajEJP9Fgy+JLIU3jzQ==
react-native-base64@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/react-native-base64/-/react-native-base64-0.2.1.tgz#3d0e73a649c4c0129f7b7695d3912456aebae847"
integrity sha512-eHgt/MA8y5ZF0aHfZ1aTPcIkDWxza9AaEk4GcpIX+ZYfZ04RcaNahO+527KR7J44/mD3efYfM23O2C1N44ByWA==
react-native-blurhash@1.1.5: react-native-blurhash@1.1.5:
version "1.1.5" version "1.1.5"
resolved "https://registry.yarnpkg.com/react-native-blurhash/-/react-native-blurhash-1.1.5.tgz#27545afb126347059a3a9324f5c3640a94b1ec53" resolved "https://registry.yarnpkg.com/react-native-blurhash/-/react-native-blurhash-1.1.5.tgz#27545afb126347059a3a9324f5c3640a94b1ec53"