Skip to content
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
81 changes: 79 additions & 2 deletions global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,27 @@ declare namespace timer {
countLocalFiles: boolean
}

type AllOption = PopupOption & AppearanceOption & StatisticsOption
/**
* The options of backup
*
* @since 1.2.0
*/
type BackupOption = {
/**
* The type 2 backup
*/
backupType: backup.Type
/**
* The auth of types, maybe ak/sk or static token
*/
backupAuths: { [type in backup.Type]?: string }
/**
* The name of this client
*/
clientName: string
}

type AllOption = PopupOption & AppearanceOption & StatisticsOption & BackupOption
/**
* @since 0.8.0
*/
Expand All @@ -114,6 +134,12 @@ declare namespace timer {
popupCounter?: {
_total?: number
}
/**
* The id of this client
*
* @since 1.2.0
*/
cid?: string
}
}

Expand Down Expand Up @@ -162,10 +188,12 @@ declare namespace timer {
date?: string
}

type RowBase = RowKey & Result

/**
* Row of each statistics result
*/
type Row = RowKey & Result & {
type Row = RowBase & {
/**
* The merged domains
*
Expand All @@ -185,6 +213,15 @@ declare namespace timer {
*/
alias?: string
}
/**
* @since 1.2.0
*/
type RemoteRow = RowBase & {
/**
* The name of client where the remote data is storaged
*/
clientName?: string
}
}

namespace limit {
Expand Down Expand Up @@ -241,6 +278,14 @@ declare namespace timer {
num: number
total: number
}
type PageQuery = {
num?: number
size?: number
}
type PageResult<T> = {
list: T[]
total: number
}
}

namespace popup {
Expand Down Expand Up @@ -323,6 +368,38 @@ declare namespace timer {
timeFormat: TimeFormat
}
}
}

/**
* @since 1.2.0
*/
namespace backup {

type Type =
| 'none'
| 'gist'

/**
* Snapshot of last backup
*/
type Snapshot = {
/**
* Timestamp
*/
ts: number
/**
* The date of the ts
*/
date: string
}

/**
* Snapshot cache
*/
type SnaptshotCache = Partial<{
[type in Type]: Snapshot
}>

type MetaCache = Partial<Record<Type, unknown>>
}
}
195 changes: 195 additions & 0 deletions src/api/gist.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
/**
* Copyright (c) 2022-present Hengyang Zhang
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/

import type { AxiosAdapter, AxiosError, AxiosResponse } from "axios"

import FIFOCache from "@util/fifo-cache"

import axios from "axios"

type BaseFile = {
filename: string
}

export type FileForm = BaseFile & {
content: string
}

export type File = BaseFile & {
type: string
language: string
raw_url: string
content?: string
}

type BaseGist<FileInfo> = {
public: boolean
description: string
files: { [filename: string]: FileInfo }
}

export type Gist = BaseGist<File> & {
id: string
}

export type GistForm = BaseGist<FileForm>

const BASE_URL = 'https://api.github.com/gists'

/**
* Cache of get requests
*/
const GET_CACHE = new FIFOCache<AxiosResponse>(20)

function createCacheAdaptor(originAdaptor: AxiosAdapter): AxiosAdapter {
return (config) => {
const { url, method } = config;
let useCache = method === 'get' && url.startsWith(BASE_URL)
if (useCache) {
// Use url and token as key
const key = url + config?.headers?.['Authorization']
return GET_CACHE.getOrSupply(key, () => originAdaptor(config))
} else {
return originAdaptor(config)
}
}
}

async function get<T>(token: string, uri: string): Promise<T> {
return new Promise(resolve => axios.get(BASE_URL + uri, {
headers: {
"Accept": "application/vnd.github+json",
"Authorization": `token ${token}`
},
// Use cache
adapter: createCacheAdaptor(axios.defaults.adapter)
}).then(response => {
if (response.status >= 200 && response.status < 300) {
return resolve(response.data as T)
} else {
return resolve(null)
}
}).catch((error: AxiosError) => {
console.log("AxisError", error)
resolve(null)
}))
}

async function post<T, R>(token: string, uri: string, body?: R): Promise<T> {
return new Promise(resolve => axios.post(BASE_URL + uri, body,
{
headers: {
"Accept": "application/vnd.github+json",
"Authorization": `token ${token}`
}
}
).then(response => {
// Clear cache if success to request
GET_CACHE.clear()
if (response.status >= 200 && response.status < 300) {
return resolve(response.data as T)
} else {
return resolve(null)
}
}).catch((error: AxiosError) => {
console.log("AxisError", error)
resolve(null)
}))
}

/**
* @param token token
* @param id id
* @returns detail of Gist
*/
export function getGist(token: string, id: string): Promise<Gist> {
return get(token, `/${id}`)
}

/**
* Find the first target gist with predicate
*
* @param token gist token
* @param predicate predicate
* @returns
*/
export async function findTarget(token: string, predicate: (gist: Gist) => boolean): Promise<Gist> {
let pageNum = 1
while (true) {
const uri = `?per_page=100&page=${pageNum}`
const gists: Gist[] = await get(token, uri)
if (!gists?.length) {
break
}
const satisfied = gists.find(predicate)
if (satisfied) {
return satisfied
}
pageNum += 1
}
return undefined
}

/**
* Create one gist
*
* @param token token
* @param gist gist info
* @returns gist info with id
*/
export function createGist(token: string, gist: GistForm): Promise<Gist> {
return post(token, "", gist)
}

/**
* Update gist
*
* @param token token
* @param gist gist
* @returns
*/
export async function updateGist(token: string, id: string, gist: GistForm): Promise<void> {
await post(token, `/${id}`, gist)
}

/**
* Get content of file
*/
export async function getJsonFileContent<T>(file: File): Promise<T> {
const content = file.content
if (content) {
return JSON.parse(content)
}
const rawUrl = file.raw_url
if (!rawUrl) {
return undefined
}
const response = await axios.get(rawUrl)
return response.data
}

/**
* Test token to process gist
*
* @returns errorMsg or null/undefined
*/
export async function testToken(token: string): Promise<string> {
return new Promise(resolve => {
axios.get(BASE_URL + '?per_page=1&page=1', {
headers: {
"Accept": "application/vnd.github+json",
"Authorization": `token ${token}`
}
}).then(response => {
if (response.status >= 200 && response.status < 300) {
resolve(undefined)
} else {
resolve(response.data?.message || 'Unknown error')
}
}).catch((error: AxiosError) => resolve((error.response?.data as any)?.message || 'Unknown error'))
})
}
28 changes: 0 additions & 28 deletions src/api/index.d.ts

This file was deleted.

26 changes: 25 additions & 1 deletion src/api/version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,33 @@
* https://opensource.org/licenses/MIT
*/

import axios, { AxiosResponse } from "axios"
import type { AxiosResponse } from 'axios'

import axios from "axios"
import { IS_CHROME, IS_EDGE, IS_FIREFOX } from "@util/constant/environment"

/**
* @since 0.1.8
*/
type FirefoxDetail = {
current_version: {
// Like 0.1.5
version: string
}
// Like '2021-06-11T08:45:32Z'
last_updated: string
}

/**
* @since 0.1.8
*/
type EdgeDetail = {
// Version like 0.1.5, without 'v' prefix
version: string
// Like '1619432502.5944779'
lastUpdateDate: string
}

async function getFirefoxVersion(): Promise<string | null> {
const response: AxiosResponse<any> = await axios.get('https://addons.mozilla.org/api/v3/addons/addon/2690100')
if (response.status !== 200) {
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/dashboard/components/top-k-visit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ const _default = defineComponent({
sortOrder: SortDirect.DESC,
mergeDate: true,
}
const top: timer.stat.Row[] = (await timerService.selectByPage(query, { pageNum: 1, pageSize: TOP_NUM }, { alias: true })).list
const top: timer.stat.Row[] = (await timerService.selectByPage(query, { num: 1, size: TOP_NUM }, { alias: true })).list
const data: _Value[] = top.map(({ time, host, alias }) => ({ name: alias || host, host, alias, value: time }))
for (let realSize = top.length; realSize < TOP_NUM; realSize++) {
data.push({ name: '', host: '', value: 0 })
Expand Down
Loading