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
185 changes: 109 additions & 76 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ tauri = "2.8.5"
tauri-build = "2.4.1"
tauri-plugin-deep-link = "2.4.3"
tauri-plugin-dialog = "2.4.0"
tauri-plugin-http = "2.5.2"
tauri-plugin-http = "2.5.7"
tauri-plugin-opener = "2.5.0"
tauri-plugin-os = "2.3.1"
tauri-plugin-single-instance = "2.3.4"
Expand Down
17 changes: 5 additions & 12 deletions apps/app-frontend/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ import { debugAnalytics, initAnalytics, trackEvent } from '@/helpers/analytics'
import { check_reachable } from '@/helpers/auth.js'
import { get_user } from '@/helpers/cache.js'
import { command_listener, warning_listener } from '@/helpers/events.js'
import { useFetch } from '@/helpers/fetch.js'
import { cancelLogin, get as getCreds, login, logout } from '@/helpers/mr_auth.ts'
import { list } from '@/helpers/profile.js'
import { get as getSettings, set as setSettings } from '@/helpers/settings.ts'
Expand Down Expand Up @@ -303,11 +302,7 @@ async function setupApp() {
}),
)

useFetch(
`https://api.modrinth.com/appCriticalAnnouncement.json?version=${version}`,
'criticalAnnouncements',
true,
)
fetch(`https://api.modrinth.com/appCriticalAnnouncement.json?version=${version}`)
.then((response) => response.json())
.then((res) => {
if (res && res.header && res.body) {
Expand All @@ -320,23 +315,21 @@ async function setupApp() {
)
})

useFetch(`https://modrinth.com/news/feed/articles.json`, 'news', true)
fetch(`https://modrinth.com/news/feed/articles.json`)
.then((response) => response.json())
.then((res) => {
if (res && res.articles) {
// Format expected by NewsArticleCard component.
news.value = res.articles
.map((article) => ({
...article,
path: article.link,
thumbnail: article.thumbnail,
title: article.title,
summary: article.summary,
date: article.date,
}))
.slice(0, 4)
}
})
.catch((error) => {
console.error('Failed to fetch news articles', error)
})

get_opening_command().then(handleCommand)
fetchCredentials()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,18 @@ async function purgeCache() {
'user',
'team',
'organization',
'file',
'loader_manifest',
'minecraft_manifest',
'categories',
'report_types',
'loaders',
'game_versions',
'donation_platforms',
'file_hash',
'file_update',
'search_results',
'search_results_v3',
]).catch(handleError)
}
Expand Down
18 changes: 0 additions & 18 deletions apps/app-frontend/src/helpers/fetch.js

This file was deleted.

19 changes: 19 additions & 0 deletions apps/app-frontend/src/helpers/worlds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,25 @@ export function isLinkedWorld(world: World): boolean {
return world.type === 'server' && !!world.linked_project_id
}

export async function getServerLatency(
address: string,
protocolVersion: ProtocolVersion | null = null,
): Promise<number | undefined> {
const pings: number[] = []
for (let i = 0; i < 3; i++) {
try {
const status = await get_server_status(address, protocolVersion)
if (status.ping != null) {
pings.push(status.ping)
}
} catch {
// Ignore individual ping failures
}
}
if (pings.length === 0) return undefined
return Math.round(pings.reduce((sum, p) => sum + p, 0) / pings.length)
}

export async function refreshServerData(
serverData: ServerData,
protocolVersion: ProtocolVersion | null,
Expand Down
23 changes: 12 additions & 11 deletions apps/app-frontend/src/pages/Browse.vue
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ import {
} from '@/helpers/profile.js'
import { get_categories, get_game_versions, get_loaders } from '@/helpers/tags'
import type { GameInstance } from '@/helpers/types'
import { get_server_status } from '@/helpers/worlds'
import { getServerLatency } from '@/helpers/worlds'
import { useBreadcrumbs } from '@/store/breadcrumbs'
import { getServerAddress, playServerProject, useInstall } from '@/store/install.js'

Expand Down Expand Up @@ -287,17 +287,18 @@ const {
} = useServerSearch({ tags, query, maxResults, currentPage })

async function pingServerHits(hits: Labrinth.Search.v3.ResultSearchProject[]) {
for (const hit of hits) {
const address = hit.minecraft_java_server?.address
if (!address) continue
get_server_status(address)
.then((status) => {
serverPings.value = { ...serverPings.value, [hit.project_id]: status.ping }
})
.catch((err) => {
const pingsToFetch = hits.filter((hit) => hit.minecraft_java_server?.address)
await Promise.all(
pingsToFetch.map(async (hit) => {
const address = hit.minecraft_java_server!.address!
try {
const latency = await getServerLatency(address)
serverPings.value = { ...serverPings.value, [hit.project_id]: latency }
} catch (err) {
console.error(`Failed to ping server ${address}:`, err)
})
}
}
}),
)
}

const previousFilterState = ref('')
Expand Down
61 changes: 20 additions & 41 deletions apps/app-frontend/src/pages/instance/Index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
<ServerPing v-if="ping" :ping="ping" />

<div
v-if="modpackContentProjectV3 && (minecraftServer?.country || ping)"
v-if="minecraftServer?.country || ping"
class="w-1.5 h-1.5 rounded-full bg-surface-5"
></div>

Expand Down Expand Up @@ -312,13 +312,13 @@ import InstanceSettingsModal from '@/components/ui/modal/InstanceSettingsModal.v
import UpdateToPlayModal from '@/components/ui/modal/UpdateToPlayModal.vue'
import NavTabs from '@/components/ui/NavTabs.vue'
import { trackEvent } from '@/helpers/analytics'
import { get_project_v3, get_version, get_version_many } from '@/helpers/cache.js'
import { get_project_v3, get_version_many } from '@/helpers/cache.js'
import { process_listener, profile_listener } from '@/helpers/events'
import { get_by_profile_path } from '@/helpers/process'
import { finish_install, get, get_full_path, get_projects, kill, run } from '@/helpers/profile'
import { finish_install, get, get_full_path, kill, run } from '@/helpers/profile'
import type { GameInstance } from '@/helpers/types'
import { showProfileInFolder } from '@/helpers/utils.js'
import { get_server_status } from '@/helpers/worlds'
import { get_server_status, getServerLatency } from '@/helpers/worlds'
import { handleSevereError } from '@/store/error.js'
import { playServerProject } from '@/store/install.js'
import { useBreadcrumbs, useLoading } from '@/store/state'
Expand Down Expand Up @@ -348,9 +348,7 @@ const exportModal = ref<InstanceType<typeof ExportModal>>()
const updateToPlayModal = ref<InstanceType<typeof UpdateToPlayModal>>()

const isServerInstance = ref(false)
const hasContent = ref(true)
const linkedProjectV3 = ref<Labrinth.Projects.v3.Project>()
const modpackContentProjectV3 = ref<Labrinth.Projects.v3.Project | null>(null)
const selected = ref<unknown[]>([])

const minecraftServer = computed(() => linkedProjectV3.value?.minecraft_server)
Expand All @@ -362,9 +360,7 @@ const ping = ref<number | undefined>(undefined)
async function fetchInstance() {
isServerInstance.value = false
linkedProjectV3.value = undefined
modpackContentProjectV3.value = null
modrinthVersions.value = []
hasContent.value = true
ping.value = undefined

instance.value = await get(route.params.id as string).catch(handleError)
Expand All @@ -382,48 +378,31 @@ async function fetchInstance() {
(a: Labrinth.Versions.v2.Version, b: Labrinth.Versions.v2.Version) =>
dayjs(b.date_published).valueOf() - dayjs(a.date_published).valueOf(),
)
if (linkedProjectV3.value?.minecraft_server != null) {
isServerInstance.value = true

const serverAddress = linkedProjectV3.value?.minecraft_java_server?.address
if (serverAddress) {
get_server_status(serverAddress)
.then((status) => {
if (status.ping != null) {
ping.value = status.ping
playersOnline.value = status.players?.online
}
})
.catch((err) => {
console.error(`Failed to ping server ${serverAddress}:`, err)
})
}
}

await fetchModpackContent()
const projects = await get_projects(instance.value!.path).catch(() => ({}))
hasContent.value = Object.keys(projects).length > 0
if (linkedProjectV3.value?.minecraft_server != null) {
isServerInstance.value = true

const serverAddress = linkedProjectV3.value?.minecraft_java_server?.address
if (serverAddress) {
try {
const status = await get_server_status(serverAddress)
const latency = await getServerLatency(serverAddress)
ping.value = latency
playersOnline.value = status.players?.online
} catch (err) {
console.error(`Failed to ping server ${serverAddress}:`, err)
}
}
}
} catch (error: Error) {
handleError(error)
} catch (error) {
handleError(error as Error)
}
}

await updatePlayState()
}

async function fetchModpackContent() {
modpackContentProjectV3.value = null
const versionId = instance.value?.linked_data?.version_id
if (!versionId) return

const contentVersion = await get_version(versionId, 'must_revalidate')
const projectId = contentVersion?.project_id
if (projectId) {
modpackContentProjectV3.value = await get_project_v3(projectId, 'must_revalidate')
}
}

async function updatePlayState() {
const runningProcesses = await get_by_profile_path(route.params.id as string).catch(handleError)

Expand Down
16 changes: 6 additions & 10 deletions apps/app-frontend/src/pages/project/Index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ import {
list as listInstances,
} from '@/helpers/profile'
import { get_categories, get_game_versions, get_loaders } from '@/helpers/tags'
import { get_server_status } from '@/helpers/worlds'
import { getServerLatency } from '@/helpers/worlds'
import { useBreadcrumbs } from '@/store/breadcrumbs'
import {
getServerAddress,
Expand Down Expand Up @@ -398,15 +398,11 @@ async function fetchProjectData() {
serverStatusOnline.value = !!projectV3.value?.minecraft_java_server?.ping?.data
if (serverAddress) {
serverPing.value = undefined
get_server_status(serverAddress)
.then((status) => {
if (status.ping != null) {
serverPing.value = status.ping
}
})
.catch((err) => {
console.error(`Failed to ping server ${serverAddress}:`, err)
})
try {
serverPing.value = await getServerLatency(serverAddress)
} catch (error) {
console.error(`Failed to ping server ${serverAddress}:`, error)
}
}

// Fetch server sidebar data (modpack version + project)
Expand Down
16 changes: 8 additions & 8 deletions apps/app-frontend/src/store/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ export const installServerProject = async (serverProjectId) => {
})
await edit_icon(profilePath, originalIconPath)

await syncServerAsWorld(profilePath, project.title, serverAddress, serverProjectId)
await syncServerProjectAsWorld(profilePath, project.title, serverAddress, serverProjectId)
}

export const getServerAddress = (javaServer) => {
Expand All @@ -337,7 +337,7 @@ export const getServerAddress = (javaServer) => {
return port !== 25565 ? `${address}:${port}` : address
}

const syncServerAsWorld = async (
const syncServerProjectAsWorld = async (
profilePath,
serverName,
serverAddress,
Expand Down Expand Up @@ -405,7 +405,7 @@ const findInstalledInstance = async (projectId) => {
return packs.find((pack) => pack.linked_data?.project_id === projectId) ?? null
}

const createVanillaInstance = async (project, gameVersion, serverAddress) => {
const createVanillaServerInstance = async (project, gameVersion, serverAddress) => {
const profilePath = await create(
project.title,
gameVersion,
Expand All @@ -420,7 +420,8 @@ const createVanillaInstance = async (project, gameVersion, serverAddress) => {
},
)

await syncServerAsWorld(profilePath, project.title, serverAddress, project.id)
//
await syncServerProjectAsWorld(profilePath, project.title, serverAddress, project.id)

return profilePath
}
Expand Down Expand Up @@ -514,6 +515,7 @@ export const playServerProject = async (projectId) => {

if (projectV3?.minecraft_server == null) {
console.warn('playServerProject failed: project is not a server project')
return
}

const content = projectV3?.minecraft_java_server?.content
Expand All @@ -529,7 +531,7 @@ export const playServerProject = async (projectId) => {
if (installStore.installingServerProjects.includes(projectId)) return
installStore.startInstallingServer(projectId)
try {
const path = await createVanillaInstance(project, recommendedGameVersion, serverAddress)
const path = await createVanillaServerInstance(project, recommendedGameVersion, serverAddress)
if (path) {
instance = await get(path)
showModpackInstallSuccess(installStore, instance, serverAddress)
Expand All @@ -543,16 +545,14 @@ export const playServerProject = async (projectId) => {
installStore.showInstallToPlayModal(projectV3, modpackVersionId, async () => {
const newInstance = await findInstalledInstance(project.id)
if (!newInstance) return
// Ensure the server is in the worlds list after modpack install
await syncServerAsWorld(newInstance.path, project.title, serverAddress, project.id)
showModpackInstallSuccess(installStore, newInstance, serverAddress)
})
return
}

if (!instance) return

await syncServerAsWorld(instance.path, project.title, serverAddress, project.id)
await syncServerProjectAsWorld(instance.path, project.title, serverAddress, project.id)

// Update existing instance if needed
if (isModpack && instance.linked_data?.version_id !== modpackVersionId) {
Expand Down
9 changes: 8 additions & 1 deletion apps/frontend/src/pages/[type]/[id].vue
Original file line number Diff line number Diff line change
Expand Up @@ -2523,6 +2523,13 @@ const navLinks = computed(() => {
const routeType = route.params.type || project.value.project_type
const projectUrl = `/${routeType}/${project.value.slug ? project.value.slug : project.value.id}`

const galleryCount =
routeType === 'server'
? project.value.gallery.filter((item) => item.name === '__mc_server_banner__').length
: project.value.gallery.length

console.log('galleryCount', galleryCount, !!currentMember.value)

return [
{
label: formatMessage(messages.descriptionTab),
Expand All @@ -2531,7 +2538,7 @@ const navLinks = computed(() => {
{
label: formatMessage(messages.galleryTab),
href: `${projectUrl}/gallery`,
shown: project.value.gallery.length > 0 || !!currentMember.value,
shown: galleryCount > 0 || !!currentMember.value,
},
{
label: formatMessage(messages.changelogTab),
Expand Down
Loading