Skip to content

Commit

Permalink
fix: Flight and telemetry does not initialize
Browse files Browse the repository at this point in the history
  • Loading branch information
ci010 committed Dec 9, 2023
1 parent 28e394a commit 248192c
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 16 deletions.
3 changes: 3 additions & 0 deletions xmcl-keystone-ui/src/composables/flights.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { InjectionKey } from 'vue'

export const kFlights: InjectionKey<Record<string, string>> = Symbol('flights')
1 change: 1 addition & 0 deletions xmcl-keystone-ui/src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<title>XMCL KeyStone</title>
<link rel="stylesheet" href="./assets/google.font.css">
<link rel="stylesheet" href="./assets/preload.css">
<script src="http://launcher/flights"></script>
</head>

<body class="flex-1 overflow-y-auto">
Expand Down
3 changes: 3 additions & 0 deletions xmcl-keystone-ui/src/windows/main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import Vue, { defineComponent, getCurrentInstance, h, provide } from 'vue'
import App from './App.vue'
import Context from './Context'
import { router } from './router'
import { kFlights } from '@/composables/flights'

// to prevent the universal drop activated on self element dragging
document.addEventListener('dragstart', (e) => {
Expand All @@ -38,6 +39,8 @@ const app = new Vue(defineComponent({
}),
})

provide(kFlights, (window as any).flights || {})

provide(kVuetify, vuetify.framework)
provide(kTaskManager, useTaskManager())
provide(kServiceFactory, useServiceFactory())
Expand Down
6 changes: 5 additions & 1 deletion xmcl-runtime/lib/app/LauncherApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ export class LauncherApp extends EventEmitter {

get version() { return this.host.getVersion() }

/**
* The launcher server protocol handler
*/
readonly protocol = new LauncherProtocolHandler()

readonly server: Server = createServer((req, res) => {
Expand Down Expand Up @@ -165,8 +168,9 @@ export class LauncherApp extends EventEmitter {
for (const plugin of plugins.concat(_plugins)) {
try {
plugin(this, builtinAppManifest, services)
} catch {
} catch (e) {
this.logger.warn(`Fail to load plugin ${plugin.name}`)
this.logger.error(e as any)
}
}

Expand Down
6 changes: 3 additions & 3 deletions xmcl-runtime/lib/plugins/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { pluginClientToken } from './pluginClientToken'
import { pluginCommonProtocol } from './pluginCommonProtocol'
import { pluginCurseforgeClient } from './pluginCurseforgeClient'
import { pluginCurseforgeModpackHandler } from './pluginCurseforgeModpackHandler'
import { pluginGFW } from './pluginGFW'
Expand All @@ -13,17 +12,18 @@ import { pluginOffineUser } from './pluginOfflineUser'
import { pluginResourcePackLink } from './pluginResourcePackLink'
import { pluginServicesHandler } from './pluginServicesHandler'
import { pluginSettings } from './pluginSettings'
import { pluginTasks } from './pluginTask'
import { pluginTasks } from './pluginTasks'
import { pluginTelemetry } from './pluginTelemetry'
import { pluginUndiciLogger } from './pluginUndiciLogger'
import { pluginUserPlaytime } from './pluginUserPlaytime'
import { pluginUserTokenStorage } from './pluginUserTokenStorage'
import { pluginWorker } from './pluginWorker'
import { pluginYggdrasilHandler } from './pluginYggdrasilHandler'
import { pluginFlights } from './pluginFlights'

export const plugins = [
pluginClientToken,
pluginCommonProtocol,
pluginFlights,
pluginGameDataPath,
pluginGFW,
pluginTasks,
Expand Down
70 changes: 59 additions & 11 deletions xmcl-runtime/lib/plugins/pluginFlights.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,70 @@ import { request } from 'undici'
import { LauncherAppPlugin } from '../app/LauncherApp'
import { kFlights } from '../entities/flights'
import { kClientToken } from '../entities/clientToken'
import { join } from 'path'
import { readFile, writeFile } from 'fs/promises'
import { read } from 'fs'
import { setTimeout } from 'timers/promises'

export const pluginFlights: LauncherAppPlugin = async (app) => {
try {
const clientSession = await app.registry.get(kClientToken)
const resp = await request(`https://api.xmcl.app/flights?version=${app.version}&locale=${app.host.getLocale()}&clientToken=${clientSession}`, {
})
if (resp.statusCode !== 200) {
throw new Error()
const logger = app.getLogger('Flights')
const fetchFlights = async (output: Record<string, string>, cachedPath: string) => {
try {
const clientSession = await app.registry.get(kClientToken)
const resp = await request(`https://api.xmcl.app/flights?version=${app.version}&locale=${app.host.getLocale()}&clientToken=${clientSession}`, {
})
if (resp.statusCode !== 200) {
throw new Error()
}
const result = await resp.body.json()
for (const [k, v] of Object.entries(result)) {
if (typeof v === 'string') {
output[k] = v
}
}
// Write to cache
await writeFile(cachedPath, JSON.stringify(output))
} catch (e) {
logger.error(e as Error)
}
const result = await resp.body.json()
const filtered = {} as Record<string, string>
for (const [k, v] of Object.entries(result)) {
if (typeof v === 'string') {
filtered[k] = v
}
const readCachedFlights = async (output: Record<string, string>, cachedPath: string) => {
try {
const cached = JSON.parse(await readFile(cachedPath, 'utf-8'))
for (const [k, v] of Object.entries(cached)) {
if (typeof v === 'string') {
output[k] = v
}
}
return false
} catch {
return true
}
}
const readFlights = async (output: Record<string, string>, cachedPath: string) => {
if (await readCachedFlights(output, cachedPath)) {
await Promise.race([fetchFlights(output, cachedPath), setTimeout(2000)])
} else {
fetchFlights(output, cachedPath).catch(() => { })
}
}
try {
const filtered = {} as Record<string, string>
const cachedPath = join(app.appDataPath, 'flights.json')
const promise = readFlights(filtered, cachedPath)

app.protocol.registerHandler('http', async ({ request, response }) => {
if (request.url.host === 'launcher' && request.url.pathname === '/flights') {
await promise
response.status = 200
const jsContent = `window.flights = ${JSON.stringify(filtered)}`
response.headers = {
'content-type': 'application/javascript',
}
response.body = jsContent
}
})

app.registry.register(kFlights, filtered)
} catch {
app.registry.register(kFlights, {})
Expand Down
4 changes: 3 additions & 1 deletion xmcl-runtime/lib/plugins/pluginTelemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { UserService } from '../services/UserService'

export const pluginTelemetry: LauncherAppPlugin = async (app) => {
process.env.APPLICATIONINSIGHTS_CONFIGURATION_CONTENT = '{}'
const logger = app.getLogger('Telemtry')
const appInsight = await import('applicationinsights')
const contract = new appInsight.Contracts.ContextTagKeys()

Expand Down Expand Up @@ -68,6 +69,7 @@ export const pluginTelemetry: LauncherAppPlugin = async (app) => {
return true
})

logger.log('Telemetry client started')
client.trackEvent({
name: 'app-start',
properties: { },
Expand All @@ -82,7 +84,7 @@ export const pluginTelemetry: LauncherAppPlugin = async (app) => {
app.registry.getOrCreate(NatService).then(async (service) => {
const state = await service.getNatState()
if (state.natDevice) {
appInsight.defaultClient.trackEvent({
client.trackEvent({
name: 'nat-device',
properties: {
natDeviceSupported: !!state.natDevice,
Expand Down

0 comments on commit 248192c

Please sign in to comment.