Begin work on new structure resolvers.
This commit is contained in:
64
package-lock.json
generated
64
package-lock.json
generated
@@ -24,16 +24,25 @@
|
|||||||
"js-tokens": "^4.0.0"
|
"js-tokens": "^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/fs-extra": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-bCtL5v9zdbQW86yexOlXWTEGvLNqWxMFyi7gQA7Gcthbezr2cPSOb8SkESVKA937QD5cIwOFLDFt0MQoXOEr9Q==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "12.6.8",
|
"version": "12.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.6.8.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.2.tgz",
|
||||||
"integrity": "sha512-aX+gFgA5GHcDi89KG5keey2zf0WfZk/HAQotEamsK2kbey+8yGKcson0hbK8E+v0NArlCJQCqMP161YhV6ZXLg==",
|
"integrity": "sha512-dyYO+f6ihZEtNPDcWNR1fkoTDf3zAK3lAABDze3mz6POyIercH0lEUawUFXlG8xaQZmm1yEBON/4TsYv/laDYg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/yargs": {
|
"@types/yargs": {
|
||||||
"version": "13.0.0",
|
"version": "13.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.2.tgz",
|
||||||
"integrity": "sha512-hY0o+kcz9M6kH32NUeb6VURghqMuCVkiUx+8Btsqhj4Hhov/hVGUx9DmBJeIkzlp1uAQK4wngQBCjqWdUUkFyA==",
|
"integrity": "sha512-lwwgizwk/bIIU+3ELORkyuOgDjCh7zuWDFqRtPPhhVgq9N1F7CvLNKg1TX4f2duwtKQ0p044Au9r1PLIXHrIzQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/yargs-parser": "*"
|
"@types/yargs-parser": "*"
|
||||||
@@ -174,9 +183,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"esutils": {
|
"esutils": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
|
||||||
"integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
|
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"find-up": {
|
"find-up": {
|
||||||
@@ -321,9 +330,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"p-limit": {
|
"p-limit": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz",
|
||||||
"integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==",
|
"integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"p-try": "^2.0.0"
|
"p-try": "^2.0.0"
|
||||||
}
|
}
|
||||||
@@ -369,27 +378,27 @@
|
|||||||
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
|
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
|
||||||
},
|
},
|
||||||
"resolve": {
|
"resolve": {
|
||||||
"version": "1.11.1",
|
"version": "1.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.1.tgz",
|
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz",
|
||||||
"integrity": "sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==",
|
"integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"path-parse": "^1.0.6"
|
"path-parse": "^1.0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rimraf": {
|
"rimraf": {
|
||||||
"version": "2.6.3",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.0.tgz",
|
||||||
"integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
|
"integrity": "sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"glob": "^7.1.3"
|
"glob": "^7.1.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"semver": {
|
"semver": {
|
||||||
"version": "5.7.0",
|
"version": "5.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||||
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
|
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"set-blocking": {
|
"set-blocking": {
|
||||||
@@ -437,9 +446,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"tslint": {
|
"tslint": {
|
||||||
"version": "5.18.0",
|
"version": "5.19.0",
|
||||||
"resolved": "https://registry.npmjs.org/tslint/-/tslint-5.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/tslint/-/tslint-5.19.0.tgz",
|
||||||
"integrity": "sha512-Q3kXkuDEijQ37nXZZLKErssQVnwCV/+23gFEMROi8IlbaBG6tXqLPQJ5Wjcyt/yHPKBC+hD5SzuGaMora+ZS6w==",
|
"integrity": "sha512-1LwwtBxfRJZnUvoS9c0uj8XQtAnyhWr9KlNvDIdB+oXyT+VpsOAaEhEgKi1HrZ8rq0ki/AAnbGSv4KM6/AfVZw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/code-frame": "^7.0.0",
|
"@babel/code-frame": "^7.0.0",
|
||||||
@@ -504,11 +513,12 @@
|
|||||||
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w=="
|
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w=="
|
||||||
},
|
},
|
||||||
"yargs": {
|
"yargs": {
|
||||||
"version": "13.3.0",
|
"version": "14.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/yargs/-/yargs-14.0.0.tgz",
|
||||||
"integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==",
|
"integrity": "sha512-ssa5JuRjMeZEUjg7bEL99AwpitxU/zWGAGpdj0di41pOEmJti8NR6kyUIJBkR78DTYNPZOU08luUo0GTHuB+ow==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"cliui": "^5.0.0",
|
"cliui": "^5.0.0",
|
||||||
|
"decamelize": "^1.2.0",
|
||||||
"find-up": "^3.0.0",
|
"find-up": "^3.0.0",
|
||||||
"get-caller-file": "^2.0.1",
|
"get-caller-file": "^2.0.1",
|
||||||
"require-directory": "^2.1.1",
|
"require-directory": "^2.1.1",
|
||||||
|
|||||||
11
package.json
11
package.json
@@ -26,15 +26,16 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/dscalzi/Nebula#readme",
|
"homepage": "https://github.com/dscalzi/Nebula#readme",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^12.6.8",
|
"@types/fs-extra": "^8.0.0",
|
||||||
"@types/yargs": "^13.0.0",
|
"@types/node": "^12.7.2",
|
||||||
"rimraf": "^2.6.3",
|
"@types/yargs": "^13.0.2",
|
||||||
"tslint": "^5.18.0",
|
"rimraf": "^3.0.0",
|
||||||
|
"tslint": "^5.19.0",
|
||||||
"typescript": "^3.5.3"
|
"typescript": "^3.5.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"adm-zip": "^0.4.13",
|
"adm-zip": "^0.4.13",
|
||||||
"fs-extra": "^8.1.0",
|
"fs-extra": "^8.1.0",
|
||||||
"yargs": "^13.3.0"
|
"yargs": "^14.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
62
src/index.ts
62
src/index.ts
@@ -1,6 +1,8 @@
|
|||||||
/* tslint:disable:no-shadowed-variable */
|
/* tslint:disable:no-shadowed-variable */
|
||||||
import { resolve } from 'path'
|
import { writeFile } from 'fs-extra'
|
||||||
|
import { resolve as resolvePath } from 'path'
|
||||||
import yargs from 'yargs'
|
import yargs from 'yargs'
|
||||||
|
import { DistributionStructure } from './model/struct/distribution.struct'
|
||||||
|
|
||||||
function rootOption(yargs: yargs.Argv) {
|
function rootOption(yargs: yargs.Argv) {
|
||||||
return yargs.option('root', {
|
return yargs.option('root', {
|
||||||
@@ -10,7 +12,29 @@ function rootOption(yargs: yargs.Argv) {
|
|||||||
global: true
|
global: true
|
||||||
})
|
})
|
||||||
.coerce({
|
.coerce({
|
||||||
root: resolve
|
root: resolvePath
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function baseUrlOption(yargs: yargs.Argv) {
|
||||||
|
return yargs.option('baseUrl', {
|
||||||
|
describe: 'Base url of your file host.',
|
||||||
|
type: 'string',
|
||||||
|
demandOption: true,
|
||||||
|
global: true
|
||||||
|
})
|
||||||
|
.coerce({
|
||||||
|
baseUrl: (arg: string) => {
|
||||||
|
// Users must provide protocol in all other instances.
|
||||||
|
if (arg.indexOf('//') === -1) {
|
||||||
|
if (arg.toLowerCase().startsWith('localhost')) {
|
||||||
|
arg = 'http://' + arg
|
||||||
|
} else {
|
||||||
|
throw new TypeError('Please provide a URL protocol (ex. http:// or https://)')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (new URL(arg)).toString()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,9 +56,15 @@ const initRootCommand: yargs.CommandModule = {
|
|||||||
yargs = rootOption(yargs)
|
yargs = rootOption(yargs)
|
||||||
return yargs
|
return yargs
|
||||||
},
|
},
|
||||||
handler: (argv) => {
|
handler: async (argv) => {
|
||||||
console.log(`Root set to ${argv.root}`)
|
console.debug(`Root set to ${argv.root}`)
|
||||||
console.log('Invoked init root.')
|
console.debug('Invoked init root.')
|
||||||
|
try {
|
||||||
|
await new DistributionStructure(argv.root as string, '').init()
|
||||||
|
console.log(`Successfully created new root at ${argv.root}`)
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Failed to init new root at ${argv.root}`, error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,8 +110,8 @@ const generateServerCommand: yargs.CommandModule = {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
handler: (argv) => {
|
handler: (argv) => {
|
||||||
console.log(`Root set to ${argv.root}`)
|
console.debug(`Root set to ${argv.root}`)
|
||||||
console.log(`Generating server ${argv.id} for Minecraft ${argv.version}.`,
|
console.debug(`Generating server ${argv.id} for Minecraft ${argv.version}.`,
|
||||||
`\n\t├ Include forge: ${argv.forge}`,
|
`\n\t├ Include forge: ${argv.forge}`,
|
||||||
`\n\t└ Include liteloader: ${argv.liteloader}`)
|
`\n\t└ Include liteloader: ${argv.liteloader}`)
|
||||||
}
|
}
|
||||||
@@ -92,12 +122,22 @@ const generateDistroCommand: yargs.CommandModule = {
|
|||||||
describe: 'Generate a distribution index from the root file structure.',
|
describe: 'Generate a distribution index from the root file structure.',
|
||||||
builder: (yargs) => {
|
builder: (yargs) => {
|
||||||
yargs = rootOption(yargs)
|
yargs = rootOption(yargs)
|
||||||
|
yargs = baseUrlOption(yargs)
|
||||||
yargs = namePositional(yargs)
|
yargs = namePositional(yargs)
|
||||||
return yargs
|
return yargs
|
||||||
},
|
},
|
||||||
handler: (argv) => {
|
handler: async (argv) => {
|
||||||
console.log(`Root set to ${argv.root}`)
|
console.debug(`Root set to ${argv.root}`)
|
||||||
console.log(`Invoked generate distro name ${argv.name}.json.`)
|
console.debug(`Base Url set to ${argv.baseUrl}`)
|
||||||
|
console.debug(`Invoked generate distro name ${argv.name}.json.`)
|
||||||
|
try {
|
||||||
|
const distributionStruct = new DistributionStructure(argv.root as string, argv.baseUrl as string)
|
||||||
|
const distro = await distributionStruct.getSpecModel()
|
||||||
|
writeFile(resolvePath(argv.root as string, `${argv.name}.json`), JSON.stringify(distro, null, 2))
|
||||||
|
console.log(distro)
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Failed to generate distribution with root ${argv.root}.`, error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,7 +162,7 @@ const validateCommand: yargs.CommandModule = {
|
|||||||
return namePositional(yargs)
|
return namePositional(yargs)
|
||||||
},
|
},
|
||||||
handler: (argv) => {
|
handler: (argv) => {
|
||||||
console.log(`Invoked validate with name ${argv.name}.json`)
|
console.debug(`Invoked validate with name ${argv.name}.json`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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: {
|
Library: {
|
||||||
id: 'Library',
|
id: Type.Library,
|
||||||
defaultExtension: 'jar'
|
defaultExtension: 'jar'
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* @deprecated Will be replaced by Types.Forge.
|
* @deprecated Will be replaced by Types.Forge.
|
||||||
*/
|
*/
|
||||||
ForgeHosted: {
|
ForgeHosted: {
|
||||||
id: 'ForgeHosted',
|
id: Type.ForgeHosted,
|
||||||
defaultExtension: 'jar'
|
defaultExtension: 'jar'
|
||||||
},
|
},
|
||||||
Forge: {
|
Forge: {
|
||||||
id: 'Forge',
|
id: Type.Forge,
|
||||||
defaultExtension: 'jar'
|
defaultExtension: 'jar'
|
||||||
},
|
},
|
||||||
LiteLoader: {
|
LiteLoader: {
|
||||||
id: 'LiteLoader',
|
id: Type.LiteLoader,
|
||||||
defaultExtension: 'jar'
|
defaultExtension: 'jar'
|
||||||
},
|
},
|
||||||
ForgeMod: {
|
ForgeMod: {
|
||||||
id: 'ForgeMod',
|
id: Type.ForgeMod,
|
||||||
defaultExtension: 'jar'
|
defaultExtension: 'jar'
|
||||||
},
|
},
|
||||||
LiteMod: {
|
LiteMod: {
|
||||||
id: 'LiteMod',
|
id: Type.LiteMod,
|
||||||
defaultExtension: 'litemod'
|
defaultExtension: 'litemod'
|
||||||
},
|
},
|
||||||
File: {
|
File: {
|
||||||
id: 'File'
|
id: Type.File
|
||||||
},
|
},
|
||||||
VersionManifest: {
|
VersionManifest: {
|
||||||
id: 'VersionManifest',
|
id: Type.VersionManifest,
|
||||||
defaultExtension: 'json'
|
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 { Distribution } from '../spec/distribution'
|
||||||
import { ModelStructure } from './model.struct'
|
import { ModelStructure } from './model.struct'
|
||||||
import { ServerStructure } from './server.struct'
|
import { ServerStructure } from './server.struct'
|
||||||
|
|
||||||
export class DistributionStructure implements ModelStructure<Distribution> {
|
export class DistributionStructure implements ModelStructure<Distribution> {
|
||||||
|
|
||||||
private servers: ServerStructure[] | undefined
|
private serverStruct: ServerStructure
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private root: string
|
private absoluteRoot: string,
|
||||||
) {}
|
private baseUrl: string
|
||||||
|
) {
|
||||||
public getServers() {
|
this.serverStruct = new ServerStructure(this.absoluteRoot, this.baseUrl)
|
||||||
return new ServerStructure(this.root).getSpecModel()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSpecModel(): Distribution {
|
public async init() {
|
||||||
return {
|
await mkdirs(this.absoluteRoot)
|
||||||
version: '1.0.0',
|
await this.serverStruct.init()
|
||||||
rss: 'TODO',
|
}
|
||||||
servers: this.getServers()
|
|
||||||
}
|
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> {
|
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 { 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(
|
constructor(
|
||||||
private root: string
|
absoluteRoot: string,
|
||||||
) {}
|
baseUrl: string
|
||||||
|
) {
|
||||||
public getSpecModel(): Server[] {
|
super(absoluteRoot, '', 'servers', baseUrl)
|
||||||
if (this.servers == null) {
|
|
||||||
this.servers = this._doSeverRetrieval()
|
|
||||||
}
|
|
||||||
return this.servers
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _doSeverRetrieval(): Server[] {
|
public async getSpecModel() {
|
||||||
const base = resolve(this.root, 'servers')
|
if (this.resolvedModels == null) {
|
||||||
return [] // TODO
|
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