Skip to content

Commit

Permalink
feat: create universal drop view
Browse files Browse the repository at this point in the history
  • Loading branch information
ci010 committed Oct 23, 2020
1 parent d471819 commit 48c6fb0
Show file tree
Hide file tree
Showing 11 changed files with 189 additions and 151 deletions.
2 changes: 1 addition & 1 deletion src/main/entities/resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ export function getResourceFromBuilder(builder: ResourceBuilder): Resource {
export function getBuilderFromResource(resource: Resource): ResourceBuilder {
return { ...resource };
}
export function mutateResource<T>(resource: Resource<T>, mutation: (builder: ResourceBuilder) => void): Resource<T> {
export function mutateResource<T extends Resource<any>>(resource: T, mutation: (builder: ResourceBuilder) => void): T {
const builder = getResourceFromBuilder(resource);
mutation(builder);
return getResourceFromBuilder(builder) as any;
Expand Down
6 changes: 4 additions & 2 deletions src/main/manager/ServiceManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import InstanceLogService from '@main/service/InstanceLogService';
import InstanceResourceService from '@main/service/InstanceResourceService';
import InstanceSavesService from '@main/service/InstanceSavesService';
import InstanceService from '@main/service/InstanceService';
import IOService from '@main/service/IOService';
import JavaService from '@main/service/JavaService';
import LaunchService from '@main/service/LaunchService';
import ResourcePackPreviewService from '@main/service/ResourcePackPreviewService';
Expand Down Expand Up @@ -114,10 +115,10 @@ export default class ServiceManager extends Manager {
if (type in servMap) {
let success = Reflect.set(serv, field, servMap[type]);
if (!success) {
throw new Error(`Cannot set service ${i} to ${Object.getPrototypeOf(serv)}`);
throw new Error(`Cannot set service ${type} to ${Object.getPrototypeOf(serv)}`);
}
} else {
throw new Error(`Cannot find service named ${i}! Which is required by ${Object.getPrototypeOf(serv).constructor.name}`);
throw new Error(`Cannot find service named ${type}! Which is required by ${Object.getPrototypeOf(serv).constructor.name}`);
}
}

Expand Down Expand Up @@ -281,6 +282,7 @@ export default class ServiceManager extends Manager {
this.registerService(InstanceIOService);
this.registerService(InstanceResourceService);
this.registerService(ResourcePackPreviewService);
this.registerService(IOService);

this.setupServices();
await this.loadServices();
Expand Down
8 changes: 3 additions & 5 deletions src/main/service/IOService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { readResourceHeader } from '@main/entities/resource';
import { pipeline, sha1, sha1ByPath } from '@main/util/fs';
import { openCompressedStreamTask } from '@main/util/zip';
import { Resource } from '@universal/entities/resource';
import { ResourceDomain } from '@universal/entities/resource.schema';
import { createHash } from 'crypto';
import { FileType, stream as fileTypeByStream } from 'file-type';
import { createReadStream, rename, stat, unlink, writeFile } from 'fs-extra';
Expand All @@ -16,12 +17,13 @@ export interface ReadFileMetadataOptions {
hint?: ExpectFileType;
size?: number;
}

export interface FileMetadata {
/**
* Where the file import from
*/
path: string;
type: BuiltinType | 'modpack' | 'unknown';
type: ResourceDomain;
fileType: FileType | 'unknown' | 'directory';
existed: boolean;
/**
Expand Down Expand Up @@ -61,10 +63,6 @@ export default class IOService extends Service {
end();
await task.execute().wait();
// zip and import
this.resourceService.addResource({
path: tempZipPath,

});
await this.resourceService.importResource({ path: tempZipPath, type: resourceType });
await unlink(tempZipPath);
} else {
Expand Down
16 changes: 9 additions & 7 deletions src/main/service/InstanceIOService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -410,13 +410,15 @@ export default class InstanceIOService extends Service {
},
}).run(ctx);

await this.resourceService.importResources(files.map((f) => ({
filePath: f.path,
url: [f.url, getCurseforgeUrl(f.projectID, f.fileID)],
source: {
curseforge: { projectId: f.projectID, fileId: f.fileID },
},
})));
await this.resourceService.importResources({
files: files.map((f) => ({
filePath: f.path,
url: [f.url, getCurseforgeUrl(f.projectID, f.fileID)],
source: {
curseforge: { projectId: f.projectID, fileId: f.fileID },
},
})),
});
return instancePath;
});
return this.submit(installCurseforgeModpack).wait();
Expand Down
84 changes: 63 additions & 21 deletions src/main/service/InstanceResourceService.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { mutateResource } from '@main/entities/resource';
import { readdirIfPresent } from '@main/util/fs';
import { InstanceResource } from '@universal/entities/instance';
import { Resource } from '@universal/entities/resource';
import { isModResource, isResourcePackResource, ModResource, Resource, ResourcePackResource, Resources } from '@universal/entities/resource';
import { copyFile, ensureDir, FSWatcher, link, unlink } from 'fs-extra';
import watch from 'node-watch';
import { basename, join } from 'path';
import IOService from './IOService';
import ResourceService from './ResourceService';
import Service, { Inject, MutationTrigger, Singleton } from './Service';

Expand All @@ -23,9 +22,6 @@ export default class InstanceResourceService extends Service {
@Inject('ResourceService')
private resourceService!: ResourceService;

@Inject('IOService')
private ioService!: IOService;

private watchingMods = '';

private modsWatcher: FSWatcher | undefined;
Expand All @@ -34,24 +30,70 @@ export default class InstanceResourceService extends Service {

private resourcepacksWatcher: FSWatcher | undefined;

private async scan(domain: string) {
private async scanMods() {
const instance = this.getters.instance;
const dir = join(instance.path, 'mods');
const files = await readdirIfPresent(dir);

const fileArgs = files.filter((file) => !file.startsWith('.')).map((file) => ({
path: join(dir, file),
url: [] as string[],
source: undefined,
type: 'mod',
}));
const resources: ModResource[] = [];
const existedResources: ModResource[] = [];
await Promise.all(fileArgs.map(async (options) => {
const existedResource = await this.resourceService.queryExistedResourceByPath(options.path);
if (!existedResource) {
const newResource = await this.resourceService.resolveResourceTask(options).execute().wait();
if (isModResource(newResource)) {
resources.push(mutateResource(newResource, (r) => { r.path = options.path; }));
} else {
this.error(`Non-mod resource found in /mods directory at ${options.path} type=${newResource.type}`);
}
} else if (isModResource(existedResource)) {
existedResources.push(existedResource);
} else {
this.error(`Non-mod resource found in /mods directory at ${options.path} type=${existedResource.type}`);
}
}));
this.resourceService.addResource(resources);
this.log(`Found ${resources.length} in instance /mods. ${resources.length} new resources and ${existedResources.length} existed resources.`);
return resources.concat(existedResources).map((r) => Object.freeze({ ...r, instancePath: instance.path }));
}

private async scanResourcepacks() {
const instance = this.getters.instance;
const dir = join(instance.path, domain);
const dir = join(instance.path, 'resourcepacks');
const files = await readdirIfPresent(dir);

const fileArgs = files.filter((file) => !file.startsWith('.')).map((file) => ({
path: join(dir, file),
url: [] as string[],
source: undefined,
type: domain,
type: 'resourcepack',
}));
const resources = await Promise.all(fileArgs.map(async (arg) => {
let { resource, imported } = await this.resourceService.resolveResourceTask(arg).execute().wait();
return { imported, resource: { ...resource, filePath: arg.path } };
const resources: ResourcePackResource[] = [];
const existedResources: ResourcePackResource[] = [];
await Promise.all(fileArgs.map(async (options) => {
const existedResource = await this.resourceService.queryExistedResourceByPath(options.path);
if (!existedResource) {
const newResource = await this.resourceService.resolveResourceTask(options).execute().wait();
if (isResourcePackResource(newResource)) {
resources.push(mutateResource(newResource, (r) => { r.path = options.path; }));
} else {
this.error(`Non-resourcepack resource found in /resourcepacks directory at ${options.path} type=${newResource.type}`);
}
} else if (isResourcePackResource(existedResource)) {
existedResources.push(existedResource);
} else {
this.error(`Non-resourcepack resource found in /resourcepacks directory at ${options.path} type=${existedResource.type}`);
}
}));
this.resourceService.cacheResources(resources.filter(r => r.imported).map(r => r.resource));
this.log(`Found ${resources.length} in instance ${domain}. ${resources.filter(r => r.imported).length} new resources and ${resources.filter(r => !r.imported).length} existed resources.`);
return resources.map((r) => r.resource);
this.resourceService.addResource(resources);
this.log(`Found ${resources.length} in instance /resourcepacks. ${resources.length} new resources and ${existedResources.length} existed resources.`);
return resources.concat(existedResources).map((r) => Object.freeze({ ...r, instancePath: instance.path }));
}

@MutationTrigger('instanceSelect')
Expand Down Expand Up @@ -87,7 +129,7 @@ export default class InstanceResourceService extends Service {
}
this.watchingMods = basePath;
await ensureDir(basePath);
this.commit('instanceMods', await this.scan('mods'));
this.commit('instanceMods', await this.scanMods());
this.modsWatcher = watch(basePath, (event, name) => {
if (name.startsWith('.')) return;
let filePath = name;
Expand All @@ -98,7 +140,7 @@ export default class InstanceResourceService extends Service {
});
} else {
this.log(`Instace mod remove ${filePath}`);
this.commit('instanceModRemove', this.state.instance.mods.find(r => r.filePath === filePath));
this.commit('instanceModRemove', this.state.instance.mods.find(r => r.path === filePath));
}
});
this.log(`Mount on instance mods: ${basePath}`);
Expand All @@ -115,7 +157,7 @@ export default class InstanceResourceService extends Service {
}
this.watchingResourcePack = basePath;
await ensureDir(basePath);
this.commit('instanceResourcepacks', await this.scan('resourcepacks'));
this.commit('instanceResourcepacks', await this.scanResourcepacks());
this.resourcepacksWatcher = watch(basePath, (event, name) => {
if (name.startsWith('.')) return;
let filePath = name;
Expand All @@ -126,7 +168,7 @@ export default class InstanceResourceService extends Service {
});
} else {
this.log(`Instace resource pack remove ${filePath}`);
this.commit('instanceResourcepackRemove', this.state.instance.resourcepacks.find(r => r.filePath === filePath));
this.commit('instanceResourcepackRemove', this.state.instance.resourcepacks.find(r => r.path === filePath));
}
});
this.log(`Mount on instance resource packs: ${basePath}`);
Expand Down Expand Up @@ -157,8 +199,8 @@ export default class InstanceResourceService extends Service {
await this.deploy({ resources: toBeDeploiedPacks });
}

async undeploy(resources: InstanceResource[]) {
async undeploy(resources: Resource[]) {
this.log(`Undeploy ${resources.length} to ${this.state.instance.path}`);
await Promise.all(resources.map(r => unlink(r.filePath)));
await Promise.all(resources.map(r => unlink(r.path)));
}
}
Loading

0 comments on commit 48c6fb0

Please sign in to comment.