Begin work on new structure resolvers.
This commit is contained in:
@@ -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
|
||||
|
||||
}
|
||||
|
||||
26
src/model/struct/basemodel.struct.ts
Normal file
26
src/model/struct/basemodel.struct.ts
Normal 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[]>
|
||||
|
||||
}
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
export interface ModelStructure<T> {
|
||||
|
||||
getSpecModel(): T
|
||||
init(): void
|
||||
|
||||
getSpecModel(): Promise<T>
|
||||
|
||||
}
|
||||
|
||||
28
src/model/struct/module/file.struct.ts
Normal file
28
src/model/struct/module/file.struct.ts
Normal 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'
|
||||
}
|
||||
|
||||
}
|
||||
28
src/model/struct/module/forgemod.struct.ts
Normal file
28
src/model/struct/module/forgemod.struct.ts
Normal 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'
|
||||
}
|
||||
|
||||
}
|
||||
29
src/model/struct/module/litemod.struct.ts
Normal file
29
src/model/struct/module/litemod.struct.ts
Normal 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'
|
||||
}
|
||||
|
||||
}
|
||||
67
src/model/struct/module/module.struct.ts
Normal file
67
src/model/struct/module/module.struct.ts
Normal 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
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user