Skip to content

Commit

Permalink
feat!: combine base services with ping
Browse files Browse the repository at this point in the history
  • Loading branch information
hywax committed Jan 4, 2024
1 parent 3d1e44c commit e07a92e
Show file tree
Hide file tree
Showing 10 changed files with 167 additions and 98 deletions.
5 changes: 3 additions & 2 deletions components/Item.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type { BaseService } from '~/types'
const props = defineProps<BaseService>()
const type = capitalize(props.type || 'base')
const component = defineAsyncComponent(() => import(`~/components/service/${type}.vue`))
const component = props.type
? defineAsyncComponent(() => import(`~/components/service/${capitalize(props.type!)}.vue`))
: resolveComponent('ServiceBase')
</script>
42 changes: 0 additions & 42 deletions components/service/Base.vue

This file was deleted.

23 changes: 0 additions & 23 deletions components/service/Ping.vue

This file was deleted.

25 changes: 25 additions & 0 deletions components/service/base/Icon.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<template>
<div :class="wrapClasses" :style="wrapStyles">
<Icon v-if="props?.name" :name="props.name" :class="iconClasses" />
<img v-else-if="props?.url" :src="props.url" alt="" :class="iconClasses">
</div>
</template>

<script setup lang="ts">
import type { ServiceIcon } from '~/types'
const props = defineProps<ServiceIcon>()
const iconClasses = 'block h-full w-full'
const wrapClasses = computed(() => ({
'bg-fg/5 dark:bg-fg/10': props?.wrap && !props?.background,
'p-2': props?.wrap,
[iconClasses]: true,
}))
const wrapStyles = computed(() => ({
background: props?.background,
color: props?.color,
}))
</script>
37 changes: 37 additions & 0 deletions components/service/base/Index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<template>
<div class="p-4 flex gap-4">
<div class="flex-shrink-0 flex">
<a :href="link" class="self-center w-16 h-16 overflow-hidden rounded-2xl border border-fg/10 dark:border-fg/15">
<slot name="icon">
<ServiceBaseIcon v-if="icon" v-bind="icon" />
</slot>
</a>
</div>
<div>
<h3 class="text-lg mt-1 font-semibold line-clamp-1 flex gap-2 items-center">
<slot name="title">
<a :href="link">{{ title }}</a>
</slot>
<slot v-if="props?.status" name="status">
<ServiceBaseStatus :ping="data?.ping" />
</slot>
</h3>

<p class="text-sm text-fg-dimmed line-clamp-1">
<slot name="description">
{{ description }}
</slot>
</p>
</div>
</div>
</template>

<script setup lang="ts">
import type { BaseService } from '~/types'
import { useServiceData } from '~/composables/services'
const props = defineProps<BaseService>()
const { data, pauseUpdate } = useServiceData<BaseService, { ping: { time: number, status: boolean } }>(props)
onBeforeUnmount(pauseUpdate)
</script>
23 changes: 23 additions & 0 deletions components/service/base/Status.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<template>
<span class="relative inline-flex z-1 h-2.5 w-2.5 rounded-full bg-green-400" :class="color">
<span class="absolute -z-1 inline-flex h-full w-full animate-ping rounded-full bg-green-400 opacity-75" :class="color" />
</span>
</template>

<script setup lang="ts">
export interface Props {
ping?: {
status: boolean
time: number
}
}
const props = defineProps<Props>()
const color = computed(() => {
if (!props.ping) {
return 'bg-neutral-400'
}
return props.ping.status ? 'bg-green-400' : 'bg-red-400'
})
</script>
29 changes: 29 additions & 0 deletions composables/services.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { BaseService } from '~/types'

export interface ServiceDataOptions {
immediate?: boolean
updateInterval?: number
}

export function useServiceData<T extends BaseService, R>(service: T, options?: ServiceDataOptions) {
const immediate = options?.immediate || true
const updateInterval = (options?.updateInterval || 60) * 1000
const type = service.type || 'base'

const { data, pending, status, refresh, execute } = useFetch<R>(`/api/services/${type}`, {
immediate,
query: { id: service.id },
timeout: 15000,
})

const { pause, resume } = useIntervalFn(refresh, updateInterval, { immediate })

return {
data,
pending,
status,
execute,
pauseUpdate: pause,
resumeUpdate: resume,
}
}
35 changes: 35 additions & 0 deletions server/api/services/base.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type { BaseService } from '~/types'

export interface State {
ping: {
status: boolean
time: number
}
}

export default defineEventHandler(async (event): Promise<State> => {
const service = await getService<BaseService>(event)
const state: State = {
ping: {
status: false,
time: -1,
},
}

if (service?.status?.enabled) {
try {
const startTime = new Date().getTime()
await $fetch(service.link, { timeout: 15000 })
const endTime = new Date().getTime()

state.ping = {
status: true,
time: endTime - startTime,
}
} catch (e) {
logger.error(e)
}
}

return state
})
18 changes: 0 additions & 18 deletions server/api/services/ping.ts

This file was deleted.

28 changes: 15 additions & 13 deletions types/services.d.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
export interface ServiceStatus {
enabled?: boolean
interval?: number
}

export interface ServiceIcon {
url?: string
name?: string
wrap?: boolean
background?: string
color?: string
}

export interface BaseService {
id: string
type?: string
title: string
description?: string
link: string
icon?: {
url?: string
name?: string
wrap?: boolean
background?: string
color?: string
}
icon?: ServiceIcon
status?: ServiceStatus
options?: Record<string, string | number | boolean>
secrets?: Record<string, string | number | boolean>
}

export interface PingService extends BaseService {
options?: {
interval?: number
}
}

0 comments on commit e07a92e

Please sign in to comment.