Object subclass: #FileServer instanceVariableNames: 'path http fs url port basePath util' package: 'FileServer'! !FileServer methodsFor: 'accessing'! basePath ^basePath ifNil: ['./'] ! basePath: aString basePath := aString ! port ^self class port ! ! !FileServer methodsFor: 'initialization'! initialize super initialize. path := self require: 'path'. http := self require: 'http'. fs := self require: 'fs'. util := self require: 'util'. url := self require: 'url' ! ! !FileServer methodsFor: 'private'! require: aModuleString "call to the require function" ^require value: aModuleString ! writeData: data toFileNamed: aFilename console log: aFilename ! ! !FileServer methodsFor: 'request handling'! respondNotFoundTo: aResponse aResponse writeHead: 404 options: #{'Content-Type' -> 'text/plain'}; write: '404 Not found'; end ! handleRequest: aRequest respondTo: aResponse aRequest method = 'PUT' ifTrue: [self handlePUTRequest: aRequest respondTo: aResponse]. aRequest method = 'GET' ifTrue:[self handleGETRequest: aRequest respondTo: aResponse]. aRequest method = 'OPTIONS' ifTrue:[self handleOPTIONSRequest: aRequest respondTo: aResponse] ! handleGETRequest: aRequest respondTo: aResponse | uri filename | uri := (url parse: aRequest url) pathname. filename := path join: self basePath with: uri. path exists: filename do: [:boolean | boolean ifFalse: [self respondNotFoundTo: aResponse] ifTrue: [self respondFileNamed: filename to: aResponse]] ! handlePUTRequest: aRequest respondTo: aResponse |stream | stream := fs createWriteStream: '.' , aRequest url. aRequest setEncoding: 'utf8'. < aRequest.on("data", function (chunk) { stream.write(chunk); }); aRequest.on("end", function () { stream.end(); aResponse.writeHead(200, "OK", { 'Content-Type': 'text/plain', 'Access-Control-Allow-Origin': '*' }); aResponse.end(); }) > ! handleOPTIONSRequest: aRequest respondTo: aResponse aResponse writeHead: 200 options: #{'Access-Control-Allow-Origin' -> '*'. 'Access-Control-Allow-Methods' -> 'GET, PUT, POST, DELETE, OPTIONS'. 'Access-Control-Allow-Headers' -> 'Content-Type, Accept'. 'Content-Length' -> 0. 'Access-Control-Max-Age' -> 10}. aResponse end ! respondFileNamed: aFilename to: aResponse | type filename | filename := aFilename. (fs statSync: aFilename) isDirectory ifTrue: [ filename := filename, 'index.html']. fs readFile: filename do: [:ex :file | ex notNil ifTrue: [self respondInternalErrorTo: aResponse] ifFalse: [ type := self class mimeTypeFor: filename. aResponse writeHead: 200 options: #{'Content-Type' -> type}; write: file binary: 'binary'; end]] ! respondInternalErrorTo: aResponse aResponse writeHead: 500 options: #{'Content-Type' -> 'text/plain'}; write: '500 Internal server error'; end ! respondOKTo: aResponse aResponse writeHead: 200 options: #{'Content-Type' -> 'text/plain'. 'Access-Control-Allow-Origin' -> '*'}. aResponse end. ! ! !FileServer methodsFor: 'starting'! startOn: aPort port := aPort. self start ! start (http createServer: [:request :response | self handleRequest: request respondTo: response]) listen: self port. console log: 'Starting file server on port ', self port asString ! ! FileServer class instanceVariableNames: 'port mimeTypes'! !FileServer class methodsFor: 'accessing'! port ^port ifNil: [4000] ! port: aNumber port := aNumber ! defaultMimeTypes ^ #{ '%' -> 'application/x-trash'. '323' -> 'text/h323'. 'abw' -> 'application/x-abiword'. 'ai' -> 'application/postscript'. 'aif' -> 'audio/x-aiff'. 'aifc' -> 'audio/x-aiff'. 'aiff' -> 'audio/x-aiff'. 'alc' -> 'chemical/x-alchemy'. 'art' -> 'image/x-jg'. 'asc' -> 'text/plain'. 'asf' -> 'video/x-ms-asf'. 'asn' -> 'chemical/x-ncbi-asn1-spec'. 'aso' -> 'chemical/x-ncbi-asn1-binary'. 'asx' -> 'video/x-ms-asf'. 'au' -> 'audio/basic'. 'avi' -> 'video/x-msvideo'. 'b' -> 'chemical/x-molconn-Z'. 'bak' -> 'application/x-trash'. 'bat' -> 'application/x-msdos-program'. 'bcpio' -> 'application/x-bcpio'. 'bib' -> 'text/x-bibtex'. 'bin' -> 'application/octet-stream'. 'bmp' -> 'image/x-ms-bmp'. 'book' -> 'application/x-maker'. 'bsd' -> 'chemical/x-crossfire'. 'c' -> 'text/x-csrc'. 'c++' -> 'text/x-c++src'. 'c3d' -> 'chemical/x-chem3d'. 'cac' -> 'chemical/x-cache'. 'cache' -> 'chemical/x-cache'. 'cascii' -> 'chemical/x-cactvs-binary'. 'cat' -> 'application/vnd.ms-pki.seccat'. 'cbin' -> 'chemical/x-cactvs-binary'. 'cc' -> 'text/x-c++src'. 'cdf' -> 'application/x-cdf'. 'cdr' -> 'image/x-coreldraw'. 'cdt' -> 'image/x-coreldrawtemplate'. 'cdx' -> 'chemical/x-cdx'. 'cdy' -> 'application/vnd.cinderella'. 'cef' -> 'chemical/x-cxf'. 'cer' -> 'chemical/x-cerius'. 'chm' -> 'chemical/x-chemdraw'. 'chrt' -> 'application/x-kchart'. 'cif' -> 'chemical/x-cif'. 'class' -> 'application/java-vm'. 'cls' -> 'text/x-tex'. 'cmdf' -> 'chemical/x-cmdf'. 'cml' -> 'chemical/x-cml'. 'cod' -> 'application/vnd.rim.cod'. 'com' -> 'application/x-msdos-program'. 'cpa' -> 'chemical/x-compass'. 'cpio' -> 'application/x-cpio'. 'cpp' -> 'text/x-c++src'. 'cpt' -> 'image/x-corelphotopaint'. 'crl' -> 'application/x-pkcs7-crl'. 'crt' -> 'application/x-x509-ca-cert'. 'csf' -> 'chemical/x-cache-csf'. 'csh' -> 'text/x-csh'. 'csm' -> 'chemical/x-csml'. 'csml' -> 'chemical/x-csml'. 'css' -> 'text/css'. 'csv' -> 'text/comma-separated-values'. 'ctab' -> 'chemical/x-cactvs-binary'. 'ctx' -> 'chemical/x-ctx'. 'cu' -> 'application/cu-seeme'. 'cub' -> 'chemical/x-gaussian-cube'. 'cxf' -> 'chemical/x-cxf'. 'cxx' -> 'text/x-c++src'. 'dat' -> 'chemical/x-mopac-input'. 'dcr' -> 'application/x-director'. 'deb' -> 'application/x-debian-package'. 'dif' -> 'video/dv'. 'diff' -> 'text/plain'. 'dir' -> 'application/x-director'. 'djv' -> 'image/vnd.djvu'. 'djvu' -> 'image/vnd.djvu'. 'dl' -> 'video/dl'. 'dll' -> 'application/x-msdos-program'. 'dmg' -> 'application/x-apple-diskimage'. 'dms' -> 'application/x-dms'. 'doc' -> 'application/msword'. 'dot' -> 'application/msword'. 'dv' -> 'video/dv'. 'dvi' -> 'application/x-dvi'. 'dx' -> 'chemical/x-jcamp-dx'. 'dxr' -> 'application/x-director'. 'emb' -> 'chemical/x-embl-dl-nucleotide'. 'embl' -> 'chemical/x-embl-dl-nucleotide'. 'ent' -> 'chemical/x-pdb'. 'eps' -> 'application/postscript'. 'etx' -> 'text/x-setext'. 'exe' -> 'application/x-msdos-program'. 'ez' -> 'application/andrew-inset'. 'fb' -> 'application/x-maker'. 'fbdoc' -> 'application/x-maker'. 'fch' -> 'chemical/x-gaussian-checkpoint'. 'fchk' -> 'chemical/x-gaussian-checkpoint'. 'fig' -> 'application/x-xfig'. 'flac' -> 'application/x-flac'. 'fli' -> 'video/fli'. 'fm' -> 'application/x-maker'. 'frame' -> 'application/x-maker'. 'frm' -> 'application/x-maker'. 'gal' -> 'chemical/x-gaussian-log'. 'gam' -> 'chemical/x-gamess-input'. 'gamin' -> 'chemical/x-gamess-input'. 'gau' -> 'chemical/x-gaussian-input'. 'gcd' -> 'text/x-pcs-gcd'. 'gcf' -> 'application/x-graphing-calculator'. 'gcg' -> 'chemical/x-gcg8-sequence'. 'gen' -> 'chemical/x-genbank'. 'gf' -> 'application/x-tex-gf'. 'gif' -> 'image/gif'. 'gjc' -> 'chemical/x-gaussian-input'. 'gjf' -> 'chemical/x-gaussian-input'. 'gl' -> 'video/gl'. 'gnumeric' -> 'application/x-gnumeric'. 'gpt' -> 'chemical/x-mopac-graph'. 'gsf' -> 'application/x-font'. 'gsm' -> 'audio/x-gsm'. 'gtar' -> 'application/x-gtar'. 'h' -> 'text/x-chdr'. 'h++' -> 'text/x-c++hdr'. 'hdf' -> 'application/x-hdf'. 'hh' -> 'text/x-c++hdr'. 'hin' -> 'chemical/x-hin'. 'hpp' -> 'text/x-c++hdr'. 'hqx' -> 'application/mac-binhex40'. 'hs' -> 'text/x-haskell'. 'hta' -> 'application/hta'. 'htc' -> 'text/x-component'. 'htm' -> 'text/html'. 'html' -> 'text/html'. 'hxx' -> 'text/x-c++hdr'. 'ica' -> 'application/x-ica'. 'ice' -> 'x-conference/x-cooltalk'. 'ico' -> 'image/x-icon'. 'ics' -> 'text/calendar'. 'icz' -> 'text/calendar'. 'ief' -> 'image/ief'. 'iges' -> 'model/iges'. 'igs' -> 'model/iges'. 'iii' -> 'application/x-iphone'. 'inp' -> 'chemical/x-gamess-input'. 'ins' -> 'application/x-internet-signup'. 'iso' -> 'application/x-iso9660-image'. 'isp' -> 'application/x-internet-signup'. 'ist' -> 'chemical/x-isostar'. 'istr' -> 'chemical/x-isostar'. 'jad' -> 'text/vnd.sun.j2me.app-descriptor'. 'jar' -> 'application/java-archive'. 'java' -> 'text/x-java'. 'jdx' -> 'chemical/x-jcamp-dx'. 'jmz' -> 'application/x-jmol'. 'jng' -> 'image/x-jng'. 'jnlp' -> 'application/x-java-jnlp-file'. 'jpe' -> 'image/jpeg'. 'jpeg' -> 'image/jpeg'. 'jpg' -> 'image/jpeg'. 'js' -> 'application/javascript'. 'kar' -> 'audio/midi'. 'key' -> 'application/pgp-keys'. 'kil' -> 'application/x-killustrator'. 'kin' -> 'chemical/x-kinemage'. 'kpr' -> 'application/x-kpresenter'. 'kpt' -> 'application/x-kpresenter'. 'ksp' -> 'application/x-kspread'. 'kwd' -> 'application/x-kword'. 'kwt' -> 'application/x-kword'. 'latex' -> 'application/x-latex'. 'lha' -> 'application/x-lha'. 'lhs' -> 'text/x-literate-haskell'. 'lsf' -> 'video/x-la-asf'. 'lsx' -> 'video/x-la-asf'. 'ltx' -> 'text/x-tex'. 'lzh' -> 'application/x-lzh'. 'lzx' -> 'application/x-lzx'. 'm3u' -> 'audio/x-mpegurl'. 'm4a' -> 'audio/mpeg'. 'maker' -> 'application/x-maker'. 'man' -> 'application/x-troff-man'. 'mcif' -> 'chemical/x-mmcif'. 'mcm' -> 'chemical/x-macmolecule'. 'mdb' -> 'application/msaccess'. 'me' -> 'application/x-troff-me'. 'mesh' -> 'model/mesh'. 'mid' -> 'audio/midi'. 'midi' -> 'audio/midi'. 'mif' -> 'application/x-mif'. 'mm' -> 'application/x-freemind'. 'mmd' -> 'chemical/x-macromodel-input'. 'mmf' -> 'application/vnd.smaf'. 'mml' -> 'text/mathml'. 'mmod' -> 'chemical/x-macromodel-input'. 'mng' -> 'video/x-mng'. 'moc' -> 'text/x-moc'. 'mol' -> 'chemical/x-mdl-molfile'. 'mol2' -> 'chemical/x-mol2'. 'moo' -> 'chemical/x-mopac-out'. 'mop' -> 'chemical/x-mopac-input'. 'mopcrt' -> 'chemical/x-mopac-input'. 'mov' -> 'video/quicktime'. 'movie' -> 'video/x-sgi-movie'. 'mp2' -> 'audio/mpeg'. 'mp3' -> 'audio/mpeg'. 'mp4' -> 'video/mp4'. 'mpc' -> 'chemical/x-mopac-input'. 'mpe' -> 'video/mpeg'. 'mpeg' -> 'video/mpeg'. 'mpega' -> 'audio/mpeg'. 'mpg' -> 'video/mpeg'. 'mpga' -> 'audio/mpeg'. 'ms' -> 'application/x-troff-ms'. 'msh' -> 'model/mesh'. 'msi' -> 'application/x-msi'. 'mvb' -> 'chemical/x-mopac-vib'. 'mxu' -> 'video/vnd.mpegurl'. 'nb' -> 'application/mathematica'. 'nc' -> 'application/x-netcdf'. 'nwc' -> 'application/x-nwc'. 'o' -> 'application/x-object'. 'oda' -> 'application/oda'. 'odb' -> 'application/vnd.oasis.opendocument.database'. 'odc' -> 'application/vnd.oasis.opendocument.chart'. 'odf' -> 'application/vnd.oasis.opendocument.formula'. 'odg' -> 'application/vnd.oasis.opendocument.graphics'. 'odi' -> 'application/vnd.oasis.opendocument.image'. 'odm' -> 'application/vnd.oasis.opendocument.text-master'. 'odp' -> 'application/vnd.oasis.opendocument.presentation'. 'ods' -> 'application/vnd.oasis.opendocument.spreadsheet'. 'odt' -> 'application/vnd.oasis.opendocument.text'. 'ogg' -> 'application/ogg'. 'old' -> 'application/x-trash'. 'oth' -> 'application/vnd.oasis.opendocument.text-web'. 'oza' -> 'application/x-oz-application'. 'p' -> 'text/x-pascal'. 'p7r' -> 'application/x-pkcs7-certreqresp'. 'pac' -> 'application/x-ns-proxy-autoconfig'. 'pas' -> 'text/x-pascal'. 'pat' -> 'image/x-coreldrawpattern'. 'pbm' -> 'image/x-portable-bitmap'. 'pcf' -> 'application/x-font'. 'pcf.Z' -> 'application/x-font'. 'pcx' -> 'image/pcx'. 'pdb' -> 'chemical/x-pdb'. 'pdf' -> 'application/pdf'. 'pfa' -> 'application/x-font'. 'pfb' -> 'application/x-font'. 'pgm' -> 'image/x-portable-graymap'. 'pgn' -> 'application/x-chess-pgn'. 'pgp' -> 'application/pgp-signature'. 'pk' -> 'application/x-tex-pk'. 'pl' -> 'text/x-perl'. 'pls' -> 'audio/x-scpls'. 'pm' -> 'text/x-perl'. 'png' -> 'image/png'. 'pnm' -> 'image/x-portable-anymap'. 'pot' -> 'text/plain'. 'ppm' -> 'image/x-portable-pixmap'. 'pps' -> 'application/vnd.ms-powerpoint'. 'ppt' -> 'application/vnd.ms-powerpoint'. 'prf' -> 'application/pics-rules'. 'prt' -> 'chemical/x-ncbi-asn1-ascii'. 'ps' -> 'application/postscript'. 'psd' -> 'image/x-photoshop'. 'psp' -> 'text/x-psp'. 'py' -> 'text/x-python'. 'pyc' -> 'application/x-python-code'. 'pyo' -> 'application/x-python-code'. 'qt' -> 'video/quicktime'. 'qtl' -> 'application/x-quicktimeplayer'. 'ra' -> 'audio/x-realaudio'. 'ram' -> 'audio/x-pn-realaudio'. 'rar' -> 'application/rar'. 'ras' -> 'image/x-cmu-raster'. 'rd' -> 'chemical/x-mdl-rdfile'. 'rdf' -> 'application/rdf+xml'. 'rgb' -> 'image/x-rgb'. 'rm' -> 'audio/x-pn-realaudio'. 'roff' -> 'application/x-troff'. 'ros' -> 'chemical/x-rosdal'. 'rpm' -> 'application/x-redhat-package-manager'. 'rss' -> 'application/rss+xml'. 'rtf' -> 'text/rtf'. 'rtx' -> 'text/richtext'. 'rxn' -> 'chemical/x-mdl-rxnfile'. 'sct' -> 'text/scriptlet'. 'sd' -> 'chemical/x-mdl-sdfile'. 'sd2' -> 'audio/x-sd2'. 'sda' -> 'application/vnd.stardivision.draw'. 'sdc' -> 'application/vnd.stardivision.calc'. 'sdd' -> 'application/vnd.stardivision.impress'. 'sdf' -> 'chemical/x-mdl-sdfile'. 'sdp' -> 'application/vnd.stardivision.impress'. 'sdw' -> 'application/vnd.stardivision.writer'. 'ser' -> 'application/java-serialized-object'. 'sgf' -> 'application/x-go-sgf'. 'sgl' -> 'application/vnd.stardivision.writer-global'. 'sh' -> 'text/x-sh'. 'shar' -> 'application/x-shar'. 'shtml' -> 'text/html'. 'sid' -> 'audio/prs.sid'. 'sik' -> 'application/x-trash'. 'silo' -> 'model/mesh'. 'sis' -> 'application/vnd.symbian.install'. 'sit' -> 'application/x-stuffit'. 'skd' -> 'application/x-koan'. 'skm' -> 'application/x-koan'. 'skp' -> 'application/x-koan'. 'skt' -> 'application/x-koan'. 'smf' -> 'application/vnd.stardivision.math'. 'smi' -> 'application/smil'. 'smil' -> 'application/smil'. 'snd' -> 'audio/basic'. 'spc' -> 'chemical/x-galactic-spc'. 'spl' -> 'application/x-futuresplash'. 'src' -> 'application/x-wais-source'. 'stc' -> 'application/vnd.sun.xml.calc.template'. 'std' -> 'application/vnd.sun.xml.draw.template'. 'sti' -> 'application/vnd.sun.xml.impress.template'. 'stl' -> 'application/vnd.ms-pki.stl'. 'stw' -> 'application/vnd.sun.xml.writer.template'. 'sty' -> 'text/x-tex'. 'sv4cpio' -> 'application/x-sv4cpio'. 'sv4crc' -> 'application/x-sv4crc'. 'svg' -> 'image/svg+xml'. 'svgz' -> 'image/svg+xml'. 'sw' -> 'chemical/x-swissprot'. 'swf' -> 'application/x-shockwave-flash'. 'swfl' -> 'application/x-shockwave-flash'. 'sxc' -> 'application/vnd.sun.xml.calc'. 'sxd' -> 'application/vnd.sun.xml.draw'. 'sxg' -> 'application/vnd.sun.xml.writer.global'. 'sxi' -> 'application/vnd.sun.xml.impress'. 'sxm' -> 'application/vnd.sun.xml.math'. 'sxw' -> 'application/vnd.sun.xml.writer'. 't' -> 'application/x-troff'. 'tar' -> 'application/x-tar'. 'taz' -> 'application/x-gtar'. 'tcl' -> 'text/x-tcl'. 'tex' -> 'text/x-tex'. 'texi' -> 'application/x-texinfo'. 'texinfo' -> 'application/x-texinfo'. 'text' -> 'text/plain'. 'tgf' -> 'chemical/x-mdl-tgf'. 'tgz' -> 'application/x-gtar'. 'tif' -> 'image/tiff'. 'tiff' -> 'image/tiff'. 'tk' -> 'text/x-tcl'. 'tm' -> 'text/texmacs'. 'torrent' -> 'application/x-bittorrent'. 'tr' -> 'application/x-troff'. 'ts' -> 'text/texmacs'. 'tsp' -> 'application/dsptype'. 'tsv' -> 'text/tab-separated-values'. 'txt' -> 'text/plain'. 'udeb' -> 'application/x-debian-package'. 'uls' -> 'text/iuls'. 'ustar' -> 'application/x-ustar'. 'val' -> 'chemical/x-ncbi-asn1-binary'. 'vcd' -> 'application/x-cdlink'. 'vcf' -> 'text/x-vcard'. 'vcs' -> 'text/x-vcalendar'. 'vmd' -> 'chemical/x-vmd'. 'vms' -> 'chemical/x-vamas-iso14976'. 'vor' -> 'application/vnd.stardivision.writer'. 'vrm' -> 'x-world/x-vrml'. 'vrml' -> 'x-world/x-vrml'. 'vsd' -> 'application/vnd.visio'. 'wad' -> 'application/x-doom'. 'wav' -> 'audio/x-wav'. 'wax' -> 'audio/x-ms-wax'. 'wbmp' -> 'image/vnd.wap.wbmp'. 'wbxml' -> 'application/vnd.wap.wbxml'. 'wk' -> 'application/x-123'. 'wm' -> 'video/x-ms-wm'. 'wma' -> 'audio/x-ms-wma'. 'wmd' -> 'application/x-ms-wmd'. 'wml' -> 'text/vnd.wap.wml'. 'wmlc' -> 'application/vnd.wap.wmlc'. 'wmls' -> 'text/vnd.wap.wmlscript'. 'wmlsc' -> 'application/vnd.wap.wmlscriptc'. 'wmv' -> 'video/x-ms-wmv'. 'wmx' -> 'video/x-ms-wmx'. 'wmz' -> 'application/x-ms-wmz'. 'wp5' -> 'application/wordperfect5.1'. 'wpd' -> 'application/wordperfect'. 'wrl' -> 'x-world/x-vrml'. 'wsc' -> 'text/scriptlet'. 'wvx' -> 'video/x-ms-wvx'. 'wz' -> 'application/x-wingz'. 'xbm' -> 'image/x-xbitmap'. 'xcf' -> 'application/x-xcf'. 'xht' -> 'application/xhtml+xml'. 'xhtml' -> 'application/xhtml+xml'. 'xlb' -> 'application/vnd.ms-excel'. 'xls' -> 'application/vnd.ms-excel'. 'xlt' -> 'application/vnd.ms-excel'. 'xml' -> 'application/xml'. 'xpi' -> 'application/x-xpinstall'. 'xpm' -> 'image/x-xpixmap'. 'xsl' -> 'application/xml'. 'xtel' -> 'chemical/x-xtel'. 'xul' -> 'application/vnd.mozilla.xul+xml'. 'xwd' -> 'image/x-xwindowdump'. 'xyz' -> 'chemical/x-xyz'. 'zip' -> 'application/zip'. 'zmt' -> 'chemical/x-mopac-input'. '~' -> 'application/x-trash' } ! mimeTypes ^mimeTypes ifNil: [mimeTypes := self defaultMimeTypes] ! mimeTypeFor: aString ^self mimeTypes at: (aString replace: '.*[\.]' with: '') ifAbsent: ['text/plain'] ! ! !FileServer class methodsFor: 'initialization'! main ^self new startOn: self port ! !