solid-contrib / solid-node-client

a nodejs client for Solid
MIT License
20 stars 8 forks source link

examples/uploadOverwrite.js #9

Closed michielbdejong closed 3 years ago

michielbdejong commented 3 years ago

Attempts to fix #8.

jeff-zucker commented 3 years ago

I'd prefer not to steer users to direct file reads with fs. Here's an example about the same length as yours that uses solid-logic and shows the power of isomorphically treating the file system as a pod. It's multi-directional, preserves content-type (so e.g. foo.jsonld would get the right content type), and has possibility of easily including ACLs and binaries.

/** Copies files from any folder to any other folder, overwriting destination   
 *  it is multi-way: pod-to-local, local-to-pod, pod-to-pod, local-to-local     
 *                                                                              
 *  USAGE : copyOverwrite <from_folder> <to_folder>                             
 *                                                                              
 *  local URLs should start with ./ and be relative to current working dir      
 *  pod URLs should be full https URLs                                          
 */                                                                             
import { SolidNodeClient } from 'solid-node-client';                            
import { SolidLogic } from 'solid-logic';                                       
import * as $rdf from 'rdflib';                                                 
const client = new SolidNodeClient();                                           
const logic = new SolidLogic({ fetch:client.fetch.bind(client) });              

async function cp(from,to) {                                                    
  from = munge(from);                                                           
  to = munge(to);                                                               
  if( to.startsWith('https') || from.startsWith('https')) await client.login(); 
  await logic.load(from);                                                       
  const promises = logic.getContainerElements($rdf.sym(from)).map(              
    async (fileNode) => {                                                       
      if(fileNode.uri.endsWith('/')) return // don't copy subdirs, TBD:recurse  
      console.log(`reading : ${fileNode.uri}`)                                  
      const res1 = await client.fetch(fileNode.uri);                            
      let ctype = res1.headers.get('content-type'); // use correct content-type 
      let content  = await res1.text();  // TBD: handle binary files                                       
      const uri = to + fileNode.uri.replace( from, '');                         
      console.log(`writing : ${uri} as ${ctype}`)                               
      const res2 = await client.fetch( uri, {                                   
        headers: {'Content-Type': ctype},                                       
        method: 'PUT',                                                          
        body: content                                                           
      });                                                                       
      console.log( uri, res2.status );                                          
      // TBD : if wac-allow user=Control, look for and copy ACL if it exists    
    }                                                                           
  );                                                                            
  await Promise.all(promises);                                                  
}                                                                               
function munge(str){                                                            
  str = str.replace(/^\.\//,'file://' + process.cwd() + '/');                   
  return str.endsWith('/') ? str : str + '/';                                   
}                                                                               
cp( process.argv[2], process.argv[3] );     
jeff-zucker commented 3 years ago

Since solid-node-client supports multiple identies, it would also be possible to write this script with two logins so that a webId on podA could copy to podB as a different webId.

jeff-zucker commented 3 years ago

Also, I do this all the time myself, but your content-type is in the wrong place. The content-type is not at the top level, it needs to be in a property of headers. I think you'll find that all the files you copied with your script end up as text/plain on NSS.

jeff-zucker commented 3 years ago

Also note that the only reason I need to import rdflib into this script is to send a namedNode to logic.getContainerElements().

jeff-zucker commented 3 years ago

I plan to write more documentation about how to use solid-node-client with other libraries (solid-logic, solid-client, rdflib, solid-file-client, ...). So I guess I am thinking about holding off on examples till that documentation is ready.

michielbdejong commented 3 years ago

Thanks! I'll close this one then.