Begin work on new structure resolvers.

This commit is contained in:
Daniel Scalzi
2019-08-21 22:25:11 -04:00
parent b942f4df59
commit 2bbf732d8e
12 changed files with 413 additions and 87 deletions

View File

@@ -1,45 +1,58 @@
export const Types: {[property: string]: Type} = {
export enum Type {
Library = 'Library',
ForgeHosted = 'ForgeHosted',
Forge = 'Forge',
LiteLoader = 'LiteLoader',
ForgeMod = 'ForgeMod',
LiteMod = 'LiteMod',
File = 'File',
VersionManifest = 'VersionManifest'
}
export interface TypeMetadata {
id: string
defaultExtension?: string
}
export const TypeMetadata: {[property: string]: TypeMetadata} = {
Library: {
id: 'Library',
id: Type.Library,
defaultExtension: 'jar'
},
/**
* @deprecated Will be replaced by Types.Forge.
*/
ForgeHosted: {
id: 'ForgeHosted',
id: Type.ForgeHosted,
defaultExtension: 'jar'
},
Forge: {
id: 'Forge',
id: Type.Forge,
defaultExtension: 'jar'
},
LiteLoader: {
id: 'LiteLoader',
id: Type.LiteLoader,
defaultExtension: 'jar'
},
ForgeMod: {
id: 'ForgeMod',
id: Type.ForgeMod,
defaultExtension: 'jar'
},
LiteMod: {
id: 'LiteMod',
id: Type.LiteMod,
defaultExtension: 'litemod'
},
File: {
id: 'File'
id: Type.File
},
VersionManifest: {
id: 'VersionManifest',
id: Type.VersionManifest,
defaultExtension: 'json'
}
}
export interface Type {
id: string
defaultExtension?: string
}

View File

@@ -0,0 +1,26 @@
import { mkdirs } from 'fs-extra'
import { join, resolve } from 'path'
import { ModelStructure } from './model.struct'
export abstract class BaseModelStructure<T> implements ModelStructure<T[]> {
protected resolvedModels: T[] | undefined
protected containerDirectory: string
constructor(
protected absoluteRoot: string,
protected relativeRoot: string,
protected structRoot: string,
protected baseUrl: string
) {
this.relativeRoot = join(relativeRoot, structRoot)
this.containerDirectory = resolve(absoluteRoot, structRoot)
}
public async init() {
mkdirs(this.containerDirectory)
}
public abstract async getSpecModel(): Promise<T[]>
}

View File

@@ -1,25 +1,32 @@
import { mkdirs } from 'fs-extra'
import { Distribution } from '../spec/distribution'
import { ModelStructure } from './model.struct'
import { ServerStructure } from './server.struct'
export class DistributionStructure implements ModelStructure<Distribution> {
private servers: ServerStructure[] | undefined
private serverStruct: ServerStructure
constructor(
private root: string
) {}
public getServers() {
return new ServerStructure(this.root).getSpecModel()
private absoluteRoot: string,
private baseUrl: string
) {
this.serverStruct = new ServerStructure(this.absoluteRoot, this.baseUrl)
}
public getSpecModel(): Distribution {
return {
version: '1.0.0',
rss: 'TODO',
servers: this.getServers()
}
public async init() {
await mkdirs(this.absoluteRoot)
await this.serverStruct.init()
}
public async getSpecModel() {
return new Promise(async (resolve) => {
resolve({
version: '1.0.0',
rss: '<FILL IN MANUALLY>',
servers: await this.serverStruct.getSpecModel()
})
}) as Promise<Distribution>
}
}

View File

@@ -1,5 +1,7 @@
export interface ModelStructure<T> {
getSpecModel(): T
init(): void
getSpecModel(): Promise<T>
}

View File

@@ -0,0 +1,28 @@
import { Stats } from 'fs'
import { Type } from '../../spec/type'
import { ModuleStructure } from './module.struct'
export class FileStructure extends ModuleStructure {
constructor(
absoluteRoot: string,
relativeRoot: string,
baseUrl: string
) {
super(absoluteRoot, relativeRoot, 'files', baseUrl, Type.File)
}
protected async getModuleId(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> {
return name
}
protected async getModuleName(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> {
return name
}
protected async getModuleUrl(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> {
return 'TODO'
}
protected async getModulePath(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> {
return 'TODO'
}
}

View File

@@ -0,0 +1,28 @@
import { Stats } from 'fs-extra'
import { Type } from '../../spec/type'
import { ModuleStructure } from './module.struct'
export class ForgeModStructure extends ModuleStructure {
constructor(
absoluteRoot: string,
relativeRoot: string,
baseUrl: string
) {
super(absoluteRoot, relativeRoot, 'forgemods', baseUrl, Type.ForgeMod)
}
protected async getModuleId(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> {
return name
}
protected async getModuleName(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> {
return name
}
protected async getModuleUrl(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> {
return 'TODO'
}
protected async getModulePath(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> {
return 'TODO'
}
}

View File

@@ -0,0 +1,29 @@
import { Stats } from 'fs-extra'
import { join } from 'path'
import { Type } from '../../spec/type'
import { ModuleStructure } from './module.struct'
export class LiteModStructure extends ModuleStructure {
constructor(
absoluteRoot: string,
relativeRoot: string,
baseUrl: string
) {
super(absoluteRoot, relativeRoot, 'litemods', baseUrl, Type.LiteMod)
}
protected async getModuleId(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> {
return name
}
protected async getModuleName(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> {
return name
}
protected async getModuleUrl(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> {
return 'TODO'
}
protected async getModulePath(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> {
return 'TODO'
}
}

View File

@@ -0,0 +1,67 @@
import { createHash } from 'crypto'
import { lstat, pathExists, readdir, readFile, Stats } from 'fs-extra'
import { resolve } from 'path'
import { Module } from '../../spec/module'
import { Type } from '../../spec/type'
import { BaseModelStructure } from '../basemodel.struct'
export abstract class ModuleStructure extends BaseModelStructure<Module> {
constructor(
absoluteRoot: string,
relativeRoot: string,
structRoot: string,
baseUrl: string,
protected type: Type
) {
super(absoluteRoot, relativeRoot, structRoot, baseUrl)
}
public async getSpecModel(): Promise<Module[]> {
if (this.resolvedModels == null) {
this.resolvedModels = await this._doModuleRetrieval()
}
return this.resolvedModels
}
protected async abstract getModuleId(name: string, path: string, stats: Stats, buf: Buffer): Promise<string>
protected async abstract getModuleName(name: string, path: string, stats: Stats, buf: Buffer): Promise<string>
protected async abstract getModuleUrl(name: string, path: string, stats: Stats, buf: Buffer): Promise<string>
protected async abstract getModulePath(name: string, path: string, stats: Stats, buf: Buffer): Promise<string>
private async _doModuleRetrieval(): Promise<Module[]> {
const accumulator: Module[] = []
if (await pathExists(this.containerDirectory)) {
const files = await readdir(this.containerDirectory)
for (const file of files) {
const filePath = resolve(this.containerDirectory, file)
const stats = await lstat(filePath)
const buf = await readFile(filePath)
if (stats.isFile()) {
accumulator.push({
id: await this.getModuleId(file, filePath, stats, buf),
name: await this.getModuleName(file, filePath, stats, buf),
type: this.type,
required: {
value: false,
def: false
},
artifact: {
size: stats.size,
MD5: createHash('md5').update(buf).digest('hex'),
url: await this.getModuleUrl(file, filePath, stats, buf),
path: await this.getModulePath(file, filePath, stats, buf)
}
})
}
}
}
return accumulator
}
}

View File

@@ -1,25 +1,100 @@
import { resolve } from 'path'
import { lstat, readdir } from 'fs-extra'
import { join, resolve as resolvePath } from 'path'
import { resolve as resolveUrl } from 'url'
import { Server } from '../spec/server'
import { ModelStructure } from './model.struct'
import { BaseModelStructure } from './basemodel.struct'
import { FileStructure } from './module/file.struct'
import { ForgeModStructure } from './module/forgemod.struct'
import { LiteModStructure } from './module/litemod.struct'
export class ServerStructure implements ModelStructure<Server[]> {
export class ServerStructure extends BaseModelStructure<Server> {
private servers: Server[] | undefined
private readonly ID_REGEX = /(.+-(.+)$)/
constructor(
private root: string
) {}
public getSpecModel(): Server[] {
if (this.servers == null) {
this.servers = this._doSeverRetrieval()
}
return this.servers
absoluteRoot: string,
baseUrl: string
) {
super(absoluteRoot, '', 'servers', baseUrl)
}
private _doSeverRetrieval(): Server[] {
const base = resolve(this.root, 'servers')
return [] // TODO
public async getSpecModel() {
if (this.resolvedModels == null) {
this.resolvedModels = await this._doSeverRetrieval()
}
return this.resolvedModels
}
private async _doSeverRetrieval(): Promise<Server[]> {
const accumulator: Server[] = []
const files = await readdir(this.containerDirectory)
for (const file of files) {
const absoluteServerRoot = resolvePath(this.containerDirectory, file)
const relativeServerRoot = join(this.relativeRoot, file)
if ((await lstat(absoluteServerRoot)).isDirectory()) {
const match = this.ID_REGEX.exec(file)
if (match == null) {
console.warn(`Server directory ${file} does not match the defined standard.`)
console.warn(`All server ids must end with -<minecraft version> (ex. -1.12.2)`)
continue
}
let iconUrl
// Resolve server icon
const subFiles = await readdir(absoluteServerRoot)
for (const subFile of subFiles) {
const caseInsensitive = subFile.toLowerCase()
if (caseInsensitive.endsWith('.jpg') || caseInsensitive.endsWith('.png')) {
iconUrl = resolveUrl(this.baseUrl, join(relativeServerRoot, subFile))
}
}
if (!iconUrl) {
console.warn(`No icon file found for server ${file}.`)
iconUrl = '<FILL IN MANUALLY>'
}
const forgeModStruct = new ForgeModStructure(absoluteServerRoot, relativeServerRoot, this.baseUrl)
const forgeModModules = await forgeModStruct.getSpecModel()
const liteModStruct = new LiteModStructure(absoluteServerRoot, relativeServerRoot, this.baseUrl)
const liteModModules = await liteModStruct.getSpecModel()
const fileStruct = new FileStructure(absoluteServerRoot, relativeServerRoot, this.baseUrl)
const fileModules = await fileStruct.getSpecModel()
const modules = [
...forgeModModules,
...liteModModules,
...fileModules
]
accumulator.push({
id: match[1],
name: '<FILL IN MANUALLY>',
description: '<FILL IN MANUALLY>',
icon: iconUrl,
version: '1.0.0',
address: '<FILL IN MANUALLY>',
minecraftVersion: match[2],
discord: {
shortId: '<FILL IN MANUALLY OR REMOVE>',
largeImageText: '<FILL IN MANUALLY OR REMOVE>',
largeImageKey: '<FILL IN MANUALLY OR REMOVE>'
},
mainServer: false,
autoconnect: false,
modules
})
} else {
console.warn(`Path ${file} in server directory is not a directory!`)
}
}
return accumulator
}
}