Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature/add_axios #53

Merged
merged 3 commits into from
Nov 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
},
"dependencies": {
"@quasar/extras": "^1.14.0",
"axios": "^1.6.2",
"core-js": "^3.6.5",
"d3": "^7.8.5",
"loglevel": "^1.8.0",
Expand Down
1 change: 1 addition & 0 deletions frontend/quasar.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ module.exports = configure(function (ctx) {
// --> boot files are part of "main.js"
// https://quasar.dev/quasar-cli/boot-files
boot: [
'axios'
],

// https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-css
Expand Down
34 changes: 34 additions & 0 deletions frontend/src/boot/axios.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { boot } from 'quasar/wrappers'
import axios from 'axios'

let API_ENDPOINT = process.env.ARCHIVARIUS_API_ENDPOINT
if (localStorage.getItem('catalogChannel') !== null) {
if (localStorage.getItem('catalogChannel') === 'production') {
API_ENDPOINT = 'https://catalog.flipperzero.one/api/v0'
} else {
API_ENDPOINT = 'https://catalog.flipp.dev/api/v0'
}
}

const api = axios.create({
baseURL: API_ENDPOINT,
timeout: 25000,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
}
})

export default boot(({ app }) => {
// for use inside Vue files (Options API) through this.$axios and this.$api

app.config.globalProperties.$axios = axios
// ^ ^ ^ this will allow you to use this.$axios (for Vue Options API form)
// so you won't necessarily have to import axios in each vue file

app.config.globalProperties.$api = api
// ^ ^ ^ this will allow you to use this.$api (for Vue Options API form)
// so you can easily perform requests against your app's API
})

export { axios, api }
2 changes: 1 addition & 1 deletion frontend/src/components/SearchBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@

<script setup>
import { ref, watch, computed } from 'vue'
import { fetchAppsShort } from '../util/util'
import { fetchAppsShort } from 'util/fetch'

import { useAppsStore } from 'src/stores/apps'
const appsStore = useAppsStore()
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/components/Updater.vue
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@
<script setup>
import { ref, defineEmits, watch, onMounted, computed } from 'vue'
import ProgressBar from './ProgressBar.vue'
import { fetchChannels, fetchFirmware, fetchRegions, unpack } from '../util/util'
import { unpack } from 'util/util'
import { fetchChannels, fetchFirmware, fetchRegions } from 'util/fetch'
import semver from 'semver'
import asyncSleep from 'simple-async-sleep'
import { PB } from '../flipper-js/protobufCompiled'
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/layouts/AppsLayout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@
import { onMounted, computed, watch } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useQuasar } from 'quasar'
import { fetchCategories, fetchAppsShort, fetchAppById } from 'util/util'
import { fetchCategories, fetchAppsShort, fetchAppById } from 'util/fetch'
import SearchBar from 'components/SearchBar.vue'
import { log } from 'composables/useLog'
import { rpcErrorHandler } from 'composables/useRpcUtils'
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/pages/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,8 @@

<script setup>
import { onUpdated, defineEmits, ref, computed, watch, onUnmounted } from 'vue'
import { bytesToSize, submitAppReport } from '../util/util'
import { bytesToSize } from 'util/util'
import { submitAppReport } from 'util/fetch'

import { useMainStore } from 'stores/main'
const mainStore = useMainStore()
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/pages/Device.vue
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
import { ref, computed, watch, onMounted, onBeforeUnmount } from 'vue'
import Updater from 'components/Updater.vue'
import asyncSleep from 'simple-async-sleep'
import { bytesToSize } from '../util/util'
import { bytesToSize } from 'util/util'
import { log } from 'composables/useLog'
import { rpcErrorHandler } from 'composables/useRpcUtils'

Expand Down Expand Up @@ -258,15 +258,15 @@ const stopScreenStream = async () => {
flags.value.screenStream = false
}
const onUpdateStage = (stage) => {
mainStore.update(stage)
mainStore.onUpdateStage(stage)
if (stage === 'start') {
flags.value.updateInProgress = true
stopScreenStream()
navigator.serial.addEventListener('connect', () => {
mainStore.update('end')
mainStore.onUpdateStage('end')
})
} else if (stage === 'end') {
mainStore.update('end')
mainStore.onUpdateStage('end')
}
}

Expand Down
12 changes: 6 additions & 6 deletions frontend/src/stores/apps.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { useRouter } from 'vue-router'
import { fetchAppsVersions, fetchAppFap } from 'util/util'
import { fetchAppsVersions, fetchAppFap } from 'util/fetch'
import asyncSleep from 'simple-async-sleep'
import { log } from 'composables/useLog'
import showNotif from 'composables/useShowNotif'
import useSetProperty from 'composables/useSetProperty'
import { rpcErrorHandler } from 'composables/useRpcUtils'
import { axios } from 'boot/axios'

import { useMainStore } from 'stores/main'

Expand Down Expand Up @@ -270,13 +271,12 @@ export const useAppsStore = defineStore('apps', () => {
})

// generate manifest
function urlContentToDataUri (url) {
return fetch(url)
.then(response => response.blob())
.then(blob => new Promise(resolve => {
async function urlContentToDataUri (url) {
return await axios.get(url, { responseType: 'blob' })
.then(({ data }) => new Promise(resolve => {
const reader = new FileReader()
reader.onload = function () { resolve(this.result) }
reader.readAsDataURL(blob)
reader.readAsDataURL(data)
}))
}
const dataUri = await urlContentToDataUri(app.currentVersion.iconUri)
Expand Down
195 changes: 195 additions & 0 deletions frontend/src/util/fetch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
import semver from 'semver'
import { axios, api } from 'boot/axios'
import { camelCaseDeep, unpack } from 'util/util'

async function fetchChannels (target) {
return await axios
.get('https://update.flipperzero.one/firmware/directory.json')
.then(({ data }) => {
const release = data.channels.find((e) => e.id === 'release')
const rc = data.channels.find((e) => e.id === 'release-candidate')
const dev = data.channels.find((e) => e.id === 'development')
const params = new URLSearchParams(location.search)
const customSource = {
url: params.get('url'),
channel: params.get('channel'),
version: params.get('version'),
target: params.get('target')
}

function formatChannel (channel) {
channel.versions.sort((a, b) => {
if (semver.lt(a.version, b.version)) return 1
else return -1
})
const output = {
version: '',
date: '',
url: '',
files: [],
changelog: ''
}
const updater = channel.versions[0].files.find(
(file) => file.target === 'f' + target && file.type === 'update_tgz'
)
if (updater) {
output.url = updater.url
}
output.version = channel.versions[0].version
output.date = new Date(channel.versions[0].timestamp * 1000)
.toISOString()
.slice(0, 10)
output.files = channel.versions[0].files.sort((a, b) => {
if (a.url.match(/[\w.]+$/g)[0] > b.url.match(/[\w.]+$/g)[0]) return 1
else return -1
})
output.changelog = channel.versions[0].changelog
return output
}

const releaseChannel = formatChannel(release)
const rcChannel = formatChannel(rc)
const devChannel = formatChannel(dev)

let customChannel
if (customSource.url) {
customChannel = {
channel: customSource.channel,
version: customSource.version,
date: new Date().toISOString().slice(0, 10),
url: customSource.url,
files: [
{
url: customSource.url,
type: 'update_tgz',
target: customSource.target
}
]
}
}
return {
release: releaseChannel,
rc: rcChannel,
dev: devChannel,
custom: customChannel
}
})
.catch(({ status }) => {
if (status >= 400) {
throw new Error('Failed to fetch firmware channels (' + status + ')')
}
})
}

async function fetchFirmware (url) {
return await axios
.get(url, { responseType: 'arraybuffer' })
.then(async ({ data }) => {
return unpack(data)
})
.catch(({ status }) => {
if (status >= 400) {
throw new Error('Failed to fetch resources (' + status + ')')
}
})
}

async function fetchRegions () {
return axios
.get('https://update.flipperzero.one/regions/api/v0/bundle')
.then(({ data }) => {
if (data.error) {
throw new Error(data.error.text)
} else if (data.success) {
return data.success
}
})
.catch(({ status }) => {
if (status >= 400) {
throw new Error('Failed to fetch region (' + status + ')')
}
})
}

async function fetchCategories (params) {
return await api.get('/category', { params }).then(({ data }) => {
return data.map((category) => camelCaseDeep(category))
})
}

async function fetchAppsShort (params) {
return await api.get('/application', { params }).then(({ data }) => {
return data.map((app) => camelCaseDeep(app))
})
}

async function fetchAppById (id, params) {
if (!params.target) {
delete params.target
}
if (!params.api) {
delete params.api
}
return await api.get(`/application/${id}`, { params }).then(({ data }) => {
return camelCaseDeep(data)
})
}

async function fetchAppFap (params) {
return await api
.get(`/application/version/${params.versionId}/build/compatible`, {
params: {
target: params.target,
api: params.api
},
responseType: 'arraybuffer'
})
.then(({ data }) => {
return data
})
.catch(({ status }) => {
if (status >= 400) {
throw new Error('Failed to fetch application build (' + status + ')')
}
})
}

async function fetchAppsVersions (uids) {
const size = 100
const subUids = []

for (let i = 0; i < Math.ceil(uids.length / size); i++) {
subUids[i] = uids.slice(i * size, i * size + size)
}

const allVersions = []
for (const sliceUids of subUids) {
await api
.post('/1/application/versions', {
application_versions: sliceUids,
limit: size
})
.then(({ data }) => allVersions.push(...data))
}

const versions = allVersions.map((version) => camelCaseDeep(version))
return versions
}

async function submitAppReport (id, report) {
return api.post(`/application/${id}/issue`, {
...report
})
}

export {
fetchChannels,
fetchFirmware,
fetchRegions,
fetchCategories,
fetchAppsShort,
fetchAppById,
fetchAppFap,
fetchAppsVersions,
submitAppReport
}
Loading