1+ import { createRequire } from 'module'
2+ const require = createRequire ( import . meta. url )
3+
4+ const $rdf = require ( 'rdflib' )
5+ import debug from './debug.mjs'
6+ import error from './http-error.mjs'
7+ import fs from 'fs'
8+ const ns = require ( 'solid-namespace' ) ( $rdf )
9+ const mime = require ( 'mime-types' )
10+ import path from 'path'
11+
12+ export { addContainerStats , addFile , addStats , readdir }
13+
14+ async function addContainerStats ( ldp , reqUri , filename , resourceGraph ) {
15+ const containerStats = await ldp . stat ( filename )
16+ addStats ( resourceGraph , reqUri , containerStats , filename )
17+ const storage = new URL ( reqUri )
18+ if ( reqUri === storage . origin + '/' ) {
19+ resourceGraph . add (
20+ resourceGraph . sym ( reqUri ) ,
21+ ns . rdf ( 'type' ) ,
22+ ns . space ( 'Storage' )
23+ )
24+ }
25+ resourceGraph . add (
26+ resourceGraph . sym ( reqUri ) ,
27+ ns . rdf ( 'type' ) ,
28+ ns . ldp ( 'BasicContainer' ) )
29+ resourceGraph . add (
30+ resourceGraph . sym ( reqUri ) ,
31+ ns . rdf ( 'type' ) ,
32+ ns . ldp ( 'Container' ) )
33+ }
34+
35+ async function addFile ( ldp , resourceGraph , containerUri , reqUri , container , file ) {
36+ // Skip .meta and .acl
37+ if ( file . endsWith ( ldp . suffixMeta ) || file . endsWith ( ldp . suffixAcl ) ) {
38+ return null
39+ }
40+
41+ const filePath = path . join ( container , file )
42+
43+ // Get file stats
44+ let stats
45+ try {
46+ stats = await ldp . stat ( filePath )
47+ } catch ( e ) {
48+ return null
49+ }
50+ const memberUri = reqUri + ( stats . isDirectory ( ) ? '/' : '' )
51+
52+ // Add fileStats to resource Graph
53+ addStats ( resourceGraph , memberUri , stats , file )
54+
55+ // Add to `contains` list
56+ resourceGraph . add (
57+ resourceGraph . sym ( containerUri ) ,
58+ ns . ldp ( 'contains' ) ,
59+ resourceGraph . sym ( memberUri ) )
60+
61+ // Set up a metaFile path
62+ // Earlier code used a .ttl file as its own meta file, which
63+ // caused massive data files to parsed as part of deirectory listings just looking for type triples
64+ const metaFile = containerUri + file + ldp . suffixMeta
65+
66+ let metadataGraph
67+ try {
68+ metadataGraph = await getMetadataGraph ( ldp , metaFile , memberUri )
69+ } catch ( err ) {
70+ metadataGraph = $rdf . graph ( )
71+ }
72+
73+ // Add Container or BasicContainer types
74+ if ( stats . isDirectory ( ) ) {
75+ resourceGraph . add (
76+ metadataGraph . sym ( memberUri ) ,
77+ ns . rdf ( 'type' ) ,
78+ ns . ldp ( 'BasicContainer' ) )
79+
80+ resourceGraph . add (
81+ metadataGraph . sym ( memberUri ) ,
82+ ns . rdf ( 'type' ) ,
83+ ns . ldp ( 'Container' ) )
84+ }
85+ // Add generic LDP type
86+ resourceGraph . add (
87+ metadataGraph . sym ( memberUri ) ,
88+ ns . rdf ( 'type' ) ,
89+ ns . ldp ( 'Resource' ) )
90+
91+ // Add type from metadataGraph
92+ metadataGraph
93+ . statementsMatching (
94+ metadataGraph . sym ( memberUri ) ,
95+ ns . rdf ( 'type' ) ,
96+ undefined )
97+ . forEach ( function ( typeStatement ) {
98+ // If the current is a file and its type is BasicContainer,
99+ // This is not possible, so do not infer its type!
100+ if (
101+ (
102+ typeStatement . object . uri !== ns . ldp ( 'BasicContainer' ) . uri &&
103+ typeStatement . object . uri !== ns . ldp ( 'Container' ) . uri
104+ ) ||
105+ ! stats . isFile ( )
106+ ) {
107+ resourceGraph . add (
108+ resourceGraph . sym ( reqUri ) ,
109+ typeStatement . predicate ,
110+ typeStatement . object )
111+ }
112+ } )
113+
114+ return null
115+ }
116+
117+ function addStats ( resourceGraph , reqUri , stats , filename ) {
118+ resourceGraph . add (
119+ resourceGraph . sym ( reqUri ) ,
120+ ns . stat ( 'mtime' ) , // Deprecate?
121+ stats . mtime . getTime ( ) / 1000 )
122+
123+ resourceGraph . add (
124+ resourceGraph . sym ( reqUri ) ,
125+ ns . dct ( 'modified' ) ,
126+ stats . mtime ) // An actual datetime value from a Date object
127+
128+ resourceGraph . add (
129+ resourceGraph . sym ( reqUri ) ,
130+ ns . stat ( 'size' ) ,
131+ stats . size )
132+
133+ if ( ! reqUri . endsWith ( '/' ) && mime . lookup ( filename ) ) { // Is the file has a well-known type,
134+ const type = 'http://www.w3.org/ns/iana/media-types/' + mime . lookup ( filename ) + '#Resource'
135+ resourceGraph . add (
136+ resourceGraph . sym ( reqUri ) ,
137+ ns . rdf ( 'type' ) , // convert MIME type to RDF
138+ resourceGraph . sym ( type )
139+ )
140+ }
141+ }
142+
143+ function readdir ( filename ) {
144+ debug . handlers ( 'GET -- Reading directory' )
145+ return new Promise ( ( resolve , reject ) => {
146+ fs . readdir ( filename , function ( err , files ) {
147+ if ( err ) {
148+ debug . handlers ( 'GET -- Error reading files: ' + err )
149+ return reject ( error ( err , 'Can\'t read container' ) )
150+ }
151+
152+ debug . handlers ( 'Files in directory: ' + files . toString ( ) . slice ( 0 , 100 ) )
153+ return resolve ( files )
154+ } )
155+ } )
156+ }
157+
158+ async function getMetadataGraph ( ldp , metaFile ) {
159+ const metaStats = await ldp . stat ( metaFile )
160+ if ( metaStats && metaStats . isFile ( ) ) {
161+ try {
162+ return await ldp . getGraph ( metaFile )
163+ } catch ( err ) {
164+ throw error ( err , 'Can\'t parse container metadata' )
165+ }
166+ } else {
167+ return $rdf . graph ( )
168+ }
169+ }
0 commit comments