Mercurial Hosting > luan
comparison src/luan/modules/IoLuan.java @ 775:1a68fc55a80c
simplify dir structure
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Fri, 26 Aug 2016 14:36:40 -0600 |
parents | core/src/luan/modules/IoLuan.java@ef0fc9ad30c1 |
children | c49980cdece6 |
comparison
equal
deleted
inserted
replaced
774:3e30cf310e56 | 775:1a68fc55a80c |
---|---|
1 package luan.modules; | |
2 | |
3 import java.io.InputStream; | |
4 import java.io.OutputStream; | |
5 import java.io.PrintStream; | |
6 import java.io.Reader; | |
7 import java.io.Writer; | |
8 import java.io.StringReader; | |
9 import java.io.BufferedReader; | |
10 import java.io.BufferedWriter; | |
11 import java.io.BufferedInputStream; | |
12 import java.io.BufferedOutputStream; | |
13 import java.io.File; | |
14 import java.io.FileInputStream; | |
15 import java.io.FileOutputStream; | |
16 import java.io.InputStreamReader; | |
17 import java.io.OutputStreamWriter; | |
18 import java.io.ByteArrayInputStream; | |
19 import java.io.DataInputStream; | |
20 import java.io.DataOutputStream; | |
21 import java.io.StringWriter; | |
22 import java.io.IOException; | |
23 import java.io.FileNotFoundException; | |
24 import java.net.URL; | |
25 import java.net.Socket; | |
26 import java.net.ServerSocket; | |
27 import java.net.InetAddress; | |
28 import java.net.Inet4Address; | |
29 import java.net.NetworkInterface; | |
30 import java.net.MalformedURLException; | |
31 import java.net.UnknownHostException; | |
32 import java.util.Enumeration; | |
33 import java.util.List; | |
34 import java.util.Map; | |
35 import luan.Luan; | |
36 import luan.LuanState; | |
37 import luan.LuanTable; | |
38 import luan.LuanFunction; | |
39 import luan.LuanJavaFunction; | |
40 import luan.LuanException; | |
41 import luan.modules.url.LuanUrl; | |
42 | |
43 | |
44 public final class IoLuan { | |
45 | |
46 private static void add(LuanTable t,String method,Class... parameterTypes) throws NoSuchMethodException { | |
47 t.rawPut( method, new LuanJavaFunction(IoLuan.class.getMethod(method,parameterTypes),null) ); | |
48 } | |
49 | |
50 public static String read_console_line(String prompt) throws IOException { | |
51 if( prompt==null ) | |
52 prompt = "> "; | |
53 return System.console().readLine(prompt); | |
54 } | |
55 | |
56 | |
57 public interface LuanWriter { | |
58 public void write(LuanState luan,Object... args) throws LuanException, IOException; | |
59 public void close() throws IOException; | |
60 } | |
61 | |
62 public static LuanTable textWriter(final PrintStream out) { | |
63 LuanWriter luanWriter = new LuanWriter() { | |
64 | |
65 public void write(LuanState luan,Object... args) throws LuanException { | |
66 for( Object obj : args ) { | |
67 out.print( luan.toString(obj) ); | |
68 } | |
69 } | |
70 | |
71 public void close() { | |
72 out.close(); | |
73 } | |
74 }; | |
75 return writer(luanWriter); | |
76 } | |
77 | |
78 public static LuanTable textWriter(final Writer out) { | |
79 LuanWriter luanWriter = new LuanWriter() { | |
80 | |
81 public void write(LuanState luan,Object... args) throws LuanException, IOException { | |
82 for( Object obj : args ) { | |
83 out.write( luan.toString(obj) ); | |
84 } | |
85 } | |
86 | |
87 public void close() throws IOException { | |
88 out.close(); | |
89 } | |
90 }; | |
91 return writer(luanWriter); | |
92 } | |
93 | |
94 private static LuanTable writer(LuanWriter luanWriter) { | |
95 LuanTable writer = new LuanTable(); | |
96 try { | |
97 writer.rawPut( "write", new LuanJavaFunction( | |
98 LuanWriter.class.getMethod( "write", LuanState.class, new Object[0].getClass() ), luanWriter | |
99 ) ); | |
100 writer.rawPut( "close", new LuanJavaFunction( | |
101 LuanWriter.class.getMethod( "close" ), luanWriter | |
102 ) ); | |
103 } catch(NoSuchMethodException e) { | |
104 throw new RuntimeException(e); | |
105 } | |
106 return writer; | |
107 } | |
108 | |
109 | |
110 public static LuanTable binaryWriter(final OutputStream out) { | |
111 LuanTable writer = new LuanTable(); | |
112 try { | |
113 writer.rawPut( "write", new LuanJavaFunction( | |
114 OutputStream.class.getMethod( "write", new byte[0].getClass() ), out | |
115 ) ); | |
116 writer.rawPut( "close", new LuanJavaFunction( | |
117 OutputStream.class.getMethod( "close" ), out | |
118 ) ); | |
119 } catch(NoSuchMethodException e) { | |
120 throw new RuntimeException(e); | |
121 } | |
122 return writer; | |
123 } | |
124 | |
125 static LuanFunction lines(final BufferedReader in) { | |
126 return new LuanFunction() { | |
127 @Override public Object call(LuanState luan,Object[] args) throws LuanException { | |
128 try { | |
129 if( args.length > 0 ) { | |
130 if( args.length > 1 || !"close".equals(args[0]) ) | |
131 throw new LuanException( "the only argument allowed is 'close'" ); | |
132 in.close(); | |
133 return null; | |
134 } | |
135 String rtn = in.readLine(); | |
136 if( rtn==null ) | |
137 in.close(); | |
138 return rtn; | |
139 } catch(IOException e) { | |
140 throw new LuanException(e); | |
141 } | |
142 } | |
143 }; | |
144 } | |
145 | |
146 static LuanFunction blocks(final InputStream in,final int blockSize) { | |
147 return new LuanFunction() { | |
148 final byte[] a = new byte[blockSize]; | |
149 | |
150 @Override public Object call(LuanState luan,Object[] args) throws LuanException { | |
151 try { | |
152 if( args.length > 0 ) { | |
153 if( args.length > 1 || !"close".equals(args[0]) ) | |
154 throw new LuanException( "the only argument allowed is 'close'" ); | |
155 in.close(); | |
156 return null; | |
157 } | |
158 if( in.read(a) == -1 ) { | |
159 in.close(); | |
160 return null; | |
161 } | |
162 return a; | |
163 } catch(IOException e) { | |
164 throw new LuanException(e); | |
165 } | |
166 } | |
167 }; | |
168 } | |
169 | |
170 | |
171 private static File objToFile(Object obj) { | |
172 if( obj instanceof String ) { | |
173 return new File((String)obj); | |
174 } | |
175 if( obj instanceof LuanTable ) { | |
176 LuanTable t = (LuanTable)obj; | |
177 Object java = t.rawGet("java"); | |
178 if( java instanceof LuanFile ) { | |
179 LuanFile luanFile = (LuanFile)java; | |
180 return luanFile.file; | |
181 } | |
182 } | |
183 return null; | |
184 } | |
185 | |
186 | |
187 public static abstract class LuanIn { | |
188 public abstract InputStream inputStream() throws IOException, LuanException; | |
189 public abstract String to_string(); | |
190 public abstract String to_uri_string(); | |
191 | |
192 public Reader reader() throws IOException, LuanException { | |
193 return new InputStreamReader(inputStream()); | |
194 } | |
195 | |
196 public String read_text() throws IOException, LuanException { | |
197 Reader in = reader(); | |
198 String s = Utils.readAll(in); | |
199 in.close(); | |
200 return s; | |
201 } | |
202 | |
203 public byte[] read_binary() throws IOException, LuanException { | |
204 InputStream in = inputStream(); | |
205 byte[] a = Utils.readAll(in); | |
206 in.close(); | |
207 return a; | |
208 } | |
209 | |
210 public LuanFunction read_lines() throws IOException, LuanException { | |
211 return lines(new BufferedReader(reader())); | |
212 } | |
213 | |
214 public LuanFunction read_blocks(Integer blockSize) throws IOException, LuanException { | |
215 int n = blockSize!=null ? blockSize : Utils.bufSize; | |
216 return blocks(inputStream(),n); | |
217 } | |
218 | |
219 public boolean exists() throws IOException, LuanException { | |
220 try { | |
221 inputStream().close(); | |
222 return true; | |
223 } catch(FileNotFoundException e) { | |
224 return false; | |
225 } | |
226 } | |
227 | |
228 public LuanTable table() { | |
229 LuanTable tbl = new LuanTable(); | |
230 try { | |
231 tbl.rawPut( "java", this ); | |
232 tbl.rawPut( "to_string", new LuanJavaFunction( | |
233 LuanIn.class.getMethod( "to_string" ), this | |
234 ) ); | |
235 tbl.rawPut( "to_uri_string", new LuanJavaFunction( | |
236 LuanIn.class.getMethod( "to_uri_string" ), this | |
237 ) ); | |
238 tbl.rawPut( "read_text", new LuanJavaFunction( | |
239 LuanIn.class.getMethod( "read_text" ), this | |
240 ) ); | |
241 tbl.rawPut( "read_binary", new LuanJavaFunction( | |
242 LuanIn.class.getMethod( "read_binary" ), this | |
243 ) ); | |
244 tbl.rawPut( "read_lines", new LuanJavaFunction( | |
245 LuanIn.class.getMethod( "read_lines" ), this | |
246 ) ); | |
247 tbl.rawPut( "read_blocks", new LuanJavaFunction( | |
248 LuanIn.class.getMethod( "read_blocks", Integer.class ), this | |
249 ) ); | |
250 tbl.rawPut( "exists", new LuanJavaFunction( | |
251 LuanIn.class.getMethod( "exists" ), this | |
252 ) ); | |
253 } catch(NoSuchMethodException e) { | |
254 throw new RuntimeException(e); | |
255 } | |
256 return tbl; | |
257 } | |
258 } | |
259 | |
260 public static final LuanIn defaultStdin = new LuanIn() { | |
261 | |
262 @Override public InputStream inputStream() { | |
263 return System.in; | |
264 } | |
265 | |
266 @Override public String to_string() { | |
267 return "<stdin>"; | |
268 } | |
269 | |
270 @Override public String to_uri_string() { | |
271 return "stdin:"; | |
272 } | |
273 | |
274 @Override public String read_text() throws IOException { | |
275 return Utils.readAll(new InputStreamReader(System.in)); | |
276 } | |
277 | |
278 @Override public byte[] read_binary() throws IOException { | |
279 return Utils.readAll(System.in); | |
280 } | |
281 | |
282 @Override public boolean exists() { | |
283 return true; | |
284 } | |
285 }; | |
286 | |
287 public static abstract class LuanIO extends LuanIn { | |
288 abstract OutputStream outputStream() throws IOException; | |
289 | |
290 public void write(Object obj) throws LuanException, IOException { | |
291 if( obj instanceof String ) { | |
292 String s = (String)obj; | |
293 Writer out = new OutputStreamWriter(outputStream()); | |
294 out.write(s); | |
295 out.close(); | |
296 return; | |
297 } | |
298 if( obj instanceof byte[] ) { | |
299 byte[] a = (byte[])obj; | |
300 OutputStream out = outputStream(); | |
301 Utils.copyAll(new ByteArrayInputStream(a),out); | |
302 out.close(); | |
303 return; | |
304 } | |
305 if( obj instanceof LuanTable ) { | |
306 LuanTable t = (LuanTable)obj; | |
307 Object java = t.rawGet("java"); | |
308 if( java instanceof LuanIn ) { | |
309 LuanIn luanIn = (LuanIn)java; | |
310 InputStream in = luanIn.inputStream(); | |
311 OutputStream out = outputStream(); | |
312 Utils.copyAll(in,out); | |
313 out.close(); | |
314 in.close(); | |
315 return; | |
316 } | |
317 } | |
318 throw new LuanException( "bad argument #1 to 'write' (string or binary or Io.uri expected)" ); | |
319 } | |
320 | |
321 public LuanTable text_writer() throws IOException { | |
322 return textWriter(new BufferedWriter(new OutputStreamWriter(outputStream()))); | |
323 } | |
324 | |
325 public LuanTable binary_writer() throws IOException { | |
326 return binaryWriter(new BufferedOutputStream(outputStream())); | |
327 } | |
328 | |
329 @Override public LuanTable table() { | |
330 LuanTable tbl = super.table(); | |
331 try { | |
332 tbl.rawPut( "write", new LuanJavaFunction( | |
333 LuanIO.class.getMethod( "write", Object.class ), this | |
334 ) ); | |
335 tbl.rawPut( "text_writer", new LuanJavaFunction( | |
336 LuanIO.class.getMethod( "text_writer" ), this | |
337 ) ); | |
338 tbl.rawPut( "binary_writer", new LuanJavaFunction( | |
339 LuanIO.class.getMethod( "binary_writer" ), this | |
340 ) ); | |
341 } catch(NoSuchMethodException e) { | |
342 throw new RuntimeException(e); | |
343 } | |
344 return tbl; | |
345 } | |
346 } | |
347 | |
348 private static final LuanIO nullIO = new LuanIO() { | |
349 private final InputStream in = new InputStream() { | |
350 @Override public int read() { | |
351 return -1; | |
352 } | |
353 }; | |
354 private final OutputStream out = new OutputStream() { | |
355 @Override public void write(int b) {} | |
356 }; | |
357 | |
358 @Override public InputStream inputStream() { | |
359 return in; | |
360 } | |
361 | |
362 @Override OutputStream outputStream() { | |
363 return out; | |
364 } | |
365 | |
366 @Override public String to_string() { | |
367 return "<null>"; | |
368 } | |
369 | |
370 @Override public String to_uri_string() { | |
371 return "null:"; | |
372 } | |
373 | |
374 }; | |
375 | |
376 public static final class LuanString extends LuanIO { | |
377 private String s; | |
378 | |
379 private LuanString(String s) { | |
380 this.s = s; | |
381 } | |
382 | |
383 @Override public InputStream inputStream() { | |
384 throw new UnsupportedOperationException(); | |
385 } | |
386 | |
387 @Override OutputStream outputStream() { | |
388 throw new UnsupportedOperationException(); | |
389 } | |
390 | |
391 @Override public String to_string() { | |
392 return "<string>"; | |
393 } | |
394 | |
395 @Override public String to_uri_string() { | |
396 return "string:" + s; | |
397 } | |
398 | |
399 @Override public Reader reader() { | |
400 return new StringReader(s); | |
401 } | |
402 | |
403 @Override public String read_text() { | |
404 return s; | |
405 } | |
406 | |
407 @Override public boolean exists() { | |
408 return true; | |
409 } | |
410 | |
411 @Override public LuanTable text_writer() throws IOException { | |
412 LuanWriter luanWriter = new LuanWriter() { | |
413 private final Writer out = new StringWriter(); | |
414 | |
415 public void write(LuanState luan,Object... args) throws LuanException, IOException { | |
416 for( Object obj : args ) { | |
417 out.write( luan.toString(obj) ); | |
418 } | |
419 } | |
420 | |
421 public void close() throws IOException { | |
422 s = out.toString(); | |
423 } | |
424 }; | |
425 return writer(luanWriter); | |
426 } | |
427 } | |
428 | |
429 public static final class LuanFile extends LuanIO { | |
430 public final File file; | |
431 | |
432 private LuanFile(LuanState luan,File file) throws LuanException { | |
433 this(file); | |
434 check(luan,"file:"+file.toString()); | |
435 } | |
436 | |
437 private LuanFile(File file) { | |
438 this.file = file; | |
439 } | |
440 | |
441 @Override public InputStream inputStream() throws IOException { | |
442 return new FileInputStream(file); | |
443 } | |
444 | |
445 @Override OutputStream outputStream() throws IOException { | |
446 return new FileOutputStream(file); | |
447 } | |
448 | |
449 @Override public String to_string() { | |
450 return file.toString(); | |
451 } | |
452 | |
453 @Override public String to_uri_string() { | |
454 return "file:" + file.toString(); | |
455 } | |
456 | |
457 public LuanTable child(LuanState luan,String name) throws LuanException { | |
458 return new LuanFile(luan,new File(file,name)).table(); | |
459 } | |
460 | |
461 public LuanTable children(LuanState luan) throws LuanException { | |
462 File[] files = file.listFiles(); | |
463 if( files==null ) | |
464 return null; | |
465 LuanTable list = new LuanTable(); | |
466 for( File f : files ) { | |
467 list.rawPut(list.rawLength()+1,new LuanFile(luan,f).table()); | |
468 } | |
469 return list; | |
470 } | |
471 | |
472 public LuanTable parent(LuanState luan) throws LuanException, IOException { | |
473 File parent = file.getParentFile(); | |
474 if( parent==null ) | |
475 parent = file.getCanonicalFile().getParentFile(); | |
476 return new LuanFile(luan,parent).table(); | |
477 } | |
478 | |
479 @Override public boolean exists() { | |
480 return file.exists(); | |
481 } | |
482 | |
483 public void rename_to(Object destObj) throws LuanException { | |
484 File dest = objToFile(destObj); | |
485 if( dest==null ) | |
486 throw new LuanException( "bad argument #1 to 'objToFile' (string or file table expected)" ); | |
487 if( !file.renameTo(dest) ) | |
488 throw new LuanException("couldn't rename file "+file+" to "+dest); | |
489 } | |
490 | |
491 public LuanTable canonical(LuanState luan) throws LuanException, IOException { | |
492 return new LuanFile(luan,file.getCanonicalFile()).table(); | |
493 } | |
494 | |
495 public LuanTable create_temp_file(LuanState luan,String prefix,String suffix) throws LuanException, IOException { | |
496 File tmp = File.createTempFile(prefix,suffix,file); | |
497 return new LuanFile(luan,tmp).table(); | |
498 } | |
499 | |
500 public void delete() throws LuanException { | |
501 if( file.exists() ) | |
502 delete(file); | |
503 } | |
504 | |
505 private static void delete(File file) throws LuanException { | |
506 File[] children = file.listFiles(); | |
507 if( children != null ) { | |
508 for( File child : children ) { | |
509 delete(child); | |
510 } | |
511 } | |
512 if( !file.delete() ) | |
513 throw new LuanException("couldn't delete file "+file); | |
514 } | |
515 | |
516 public void mkdir() throws LuanException { | |
517 if( !file.isDirectory() ) { | |
518 if( !file.mkdirs() ) | |
519 throw new LuanException("couldn't make directory "+file); | |
520 } | |
521 } | |
522 | |
523 public void set_last_modified(long time) throws LuanException { | |
524 if( !file.setLastModified(time) ) | |
525 throw new LuanException("couldn't set_last_modified on "+file); | |
526 } | |
527 | |
528 @Override public LuanTable table() { | |
529 LuanTable tbl = super.table(); | |
530 try { | |
531 tbl.rawPut( "name", new LuanJavaFunction( | |
532 File.class.getMethod( "getName" ), file | |
533 ) ); | |
534 tbl.rawPut( "is_directory", new LuanJavaFunction( | |
535 File.class.getMethod( "isDirectory" ), file | |
536 ) ); | |
537 tbl.rawPut( "is_file", new LuanJavaFunction( | |
538 File.class.getMethod( "isFile" ), file | |
539 ) ); | |
540 tbl.rawPut( "delete", new LuanJavaFunction( | |
541 LuanFile.class.getMethod( "delete" ), this | |
542 ) ); | |
543 tbl.rawPut( "delete_on_exit", new LuanJavaFunction( | |
544 File.class.getMethod( "deleteOnExit" ), file | |
545 ) ); | |
546 tbl.rawPut( "mkdir", new LuanJavaFunction( | |
547 LuanFile.class.getMethod( "mkdir" ), this | |
548 ) ); | |
549 tbl.rawPut( "last_modified", new LuanJavaFunction( | |
550 File.class.getMethod( "lastModified" ), file | |
551 ) ); | |
552 tbl.rawPut( "set_last_modified", new LuanJavaFunction( | |
553 LuanFile.class.getMethod( "set_last_modified", Long.TYPE ), this | |
554 ) ); | |
555 tbl.rawPut( "length", new LuanJavaFunction( | |
556 File.class.getMethod( "length" ), file | |
557 ) ); | |
558 tbl.rawPut( "child", new LuanJavaFunction( | |
559 LuanFile.class.getMethod( "child", LuanState.class, String.class ), this | |
560 ) ); | |
561 tbl.rawPut( "children", new LuanJavaFunction( | |
562 LuanFile.class.getMethod( "children", LuanState.class ), this | |
563 ) ); | |
564 tbl.rawPut( "parent", new LuanJavaFunction( | |
565 LuanFile.class.getMethod( "parent", LuanState.class ), this | |
566 ) ); | |
567 tbl.rawPut( "rename_to", new LuanJavaFunction( | |
568 LuanFile.class.getMethod( "rename_to", Object.class ), this | |
569 ) ); | |
570 tbl.rawPut( "canonical", new LuanJavaFunction( | |
571 LuanFile.class.getMethod( "canonical", LuanState.class ), this | |
572 ) ); | |
573 tbl.rawPut( "create_temp_file", new LuanJavaFunction( | |
574 LuanFile.class.getMethod( "create_temp_file", LuanState.class, String.class, String.class ), this | |
575 ) ); | |
576 } catch(NoSuchMethodException e) { | |
577 throw new RuntimeException(e); | |
578 } | |
579 return tbl; | |
580 } | |
581 } | |
582 | |
583 public static LuanTable null_() { | |
584 return nullIO.table(); | |
585 } | |
586 | |
587 public static LuanTable string(String s) throws LuanException { | |
588 Utils.checkNotNull(s); | |
589 return new LuanString(s).table(); | |
590 } | |
591 | |
592 public static LuanTable file(LuanState luan,String name) throws LuanException { | |
593 File file = new File(name); | |
594 return new LuanFile(file).table(); | |
595 } | |
596 | |
597 public static LuanTable classpath(LuanState luan,String name) throws LuanException { | |
598 if( name.contains("//") ) | |
599 return null; | |
600 String path = name; | |
601 check(luan,"classpath:"+path); | |
602 URL url; | |
603 if( !path.contains("#") ) { | |
604 url = ClassLoader.getSystemResource(path); | |
605 } else { | |
606 String[] a = path.split("#"); | |
607 url = ClassLoader.getSystemResource(a[0]); | |
608 if( url==null ) { | |
609 for( int i=1; i<a.length; i++ ) { | |
610 url = ClassLoader.getSystemResource(a[0]+"/"+a[i]); | |
611 if( url != null ) { | |
612 try { | |
613 url = new URL(url,"."); | |
614 } catch(MalformedURLException e) { | |
615 throw new RuntimeException(e); | |
616 } | |
617 break; | |
618 } | |
619 } | |
620 } | |
621 } | |
622 if( url != null ) | |
623 return new LuanUrl(luan,url,null).table(); | |
624 | |
625 return null; | |
626 } | |
627 | |
628 private static LuanTable url(LuanState luan,String url,LuanTable options) throws IOException, LuanException { | |
629 return new LuanUrl(luan,new URL(url),options).table(); | |
630 } | |
631 | |
632 public static LuanTable http(LuanState luan,String path,LuanTable options) throws IOException, LuanException { | |
633 return url(luan,"http:"+path,options); | |
634 } | |
635 | |
636 public static LuanTable https(LuanState luan,String path,LuanTable options) throws IOException, LuanException { | |
637 return url(luan,"https:"+path,options); | |
638 } | |
639 | |
640 public static LuanTable luan(LuanState luan,String path) throws LuanException { | |
641 return classpath( luan, "luan/modules/" + path ); | |
642 } | |
643 | |
644 public static LuanTable stdin(LuanState luan) throws LuanException { | |
645 LuanTable io = (LuanTable)PackageLuan.require(luan,"luan:Io.luan"); | |
646 return (LuanTable)io.get(luan,"stdin"); | |
647 } | |
648 | |
649 public static LuanTable newSchemes() { | |
650 LuanTable schemes = new LuanTable(); | |
651 try { | |
652 schemes.rawPut( "null", new LuanJavaFunction(IoLuan.class.getMethod("null_"),null) ); | |
653 add( schemes, "string", String.class ); | |
654 add( schemes, "file", LuanState.class, String.class ); | |
655 add( schemes, "classpath", LuanState.class, String.class ); | |
656 add( schemes, "socket", String.class ); | |
657 add( schemes, "http", LuanState.class, String.class, LuanTable.class ); | |
658 add( schemes, "https", LuanState.class, String.class, LuanTable.class ); | |
659 add( schemes, "luan", LuanState.class, String.class ); | |
660 add( schemes, "stdin", LuanState.class ); | |
661 add( schemes, "os", LuanState.class, String.class, LuanTable.class ); | |
662 } catch(NoSuchMethodException e) { | |
663 throw new RuntimeException(e); | |
664 } | |
665 return schemes; | |
666 } | |
667 | |
668 private static LuanTable schemes(LuanState luan) throws LuanException { | |
669 LuanTable t = (LuanTable)PackageLuan.loaded(luan).rawGet("luan:Io.luan"); | |
670 if( t == null ) | |
671 return newSchemes(); | |
672 t = (LuanTable)t.get(luan,"schemes"); | |
673 if( t == null ) | |
674 return newSchemes(); | |
675 return t; | |
676 } | |
677 | |
678 public static LuanTable uri(LuanState luan,String name,LuanTable options) throws LuanException { | |
679 int i = name.indexOf(':'); | |
680 if( i == -1 ) | |
681 throw new LuanException( "invalid Io.uri name '"+name+"', missing scheme" ); | |
682 String scheme = name.substring(0,i); | |
683 String location = name.substring(i+1); | |
684 LuanTable schemes = schemes(luan); | |
685 LuanFunction opener = (LuanFunction)schemes.get(luan,scheme); | |
686 if( opener == null ) | |
687 throw new LuanException( "invalid scheme '"+scheme+"' in '"+name+"'" ); | |
688 return (LuanTable)Luan.first(opener.call(luan,new Object[]{location,options})); | |
689 } | |
690 | |
691 public static final class LuanSocket extends LuanIO { | |
692 public final Socket socket; | |
693 | |
694 private LuanSocket(String host,int port) throws LuanException { | |
695 try { | |
696 this.socket = new Socket(host,port); | |
697 } catch(IOException e) { | |
698 throw new LuanException(e.toString()); | |
699 } | |
700 } | |
701 | |
702 private LuanSocket(Socket socket) { | |
703 this.socket = socket; | |
704 } | |
705 | |
706 @Override public InputStream inputStream() throws IOException { | |
707 return socket.getInputStream(); | |
708 } | |
709 | |
710 @Override OutputStream outputStream() throws IOException { | |
711 return socket.getOutputStream(); | |
712 } | |
713 | |
714 @Override public String to_string() { | |
715 return socket.toString(); | |
716 } | |
717 | |
718 @Override public String to_uri_string() { | |
719 throw new UnsupportedOperationException(); | |
720 } | |
721 } | |
722 | |
723 public static LuanTable socket(String name) throws LuanException, IOException { | |
724 int i = name.indexOf(':'); | |
725 if( i == -1 ) | |
726 throw new LuanException( "invalid socket '"+name+"', format is: <host>:<port>" ); | |
727 String host = name.substring(0,i); | |
728 String portStr = name.substring(i+1); | |
729 int port = Integer.parseInt(portStr); | |
730 return new LuanSocket(host,port).table(); | |
731 } | |
732 | |
733 public static LuanFunction socket_server(int port) throws IOException { | |
734 final ServerSocket ss = new ServerSocket(port); | |
735 return new LuanFunction() { | |
736 @Override public Object call(LuanState luan,Object[] args) throws LuanException { | |
737 try { | |
738 if( args.length > 0 ) { | |
739 if( args.length > 1 || !"close".equals(args[0]) ) | |
740 throw new LuanException( "the only argument allowed is 'close'" ); | |
741 ss.close(); | |
742 return null; | |
743 } | |
744 return new LuanSocket(ss.accept()).table(); | |
745 } catch(IOException e) { | |
746 throw new LuanException(e); | |
747 } | |
748 } | |
749 }; | |
750 } | |
751 | |
752 | |
753 public static final class LuanOs extends LuanIO { | |
754 private final String cmd; | |
755 private final Process proc; | |
756 | |
757 private LuanOs(LuanState luan,String cmd,LuanTable options) throws IOException, LuanException { | |
758 this.cmd = cmd; | |
759 File dir = null; | |
760 if( options != null ) { | |
761 Map map = options.asMap(luan); | |
762 Object obj = map.remove("dir"); | |
763 dir = objToFile(obj); | |
764 if( dir==null ) | |
765 throw new LuanException( "bad option 'dir' (string or file table expected)" ); | |
766 if( !map.isEmpty() ) | |
767 throw new LuanException( "unrecognized options: "+map ); | |
768 } | |
769 this.proc = Runtime.getRuntime().exec(cmd,null,dir); | |
770 } | |
771 | |
772 @Override public InputStream inputStream() throws IOException { | |
773 return proc.getInputStream(); | |
774 } | |
775 | |
776 @Override OutputStream outputStream() throws IOException { | |
777 return proc.getOutputStream(); | |
778 } | |
779 | |
780 @Override public String to_string() { | |
781 return proc.toString(); | |
782 } | |
783 | |
784 @Override public String to_uri_string() { | |
785 throw new UnsupportedOperationException(); | |
786 } | |
787 | |
788 @Override public boolean exists() { | |
789 return true; | |
790 } | |
791 | |
792 public void wait_for() | |
793 throws IOException, LuanException | |
794 { | |
795 try { | |
796 proc.waitFor(); | |
797 } catch(InterruptedException e) { | |
798 throw new RuntimeException(e); | |
799 } | |
800 int exitVal = proc.exitValue(); | |
801 if( exitVal != 0 ) { | |
802 Reader err = new InputStreamReader(proc.getErrorStream()); | |
803 String error = "error in: "+cmd+"\n"+Utils.readAll(err); | |
804 err.close(); | |
805 throw new LuanException(error); | |
806 } | |
807 } | |
808 | |
809 @Override public String read_text() throws IOException, LuanException { | |
810 String s = super.read_text(); | |
811 wait_for(); | |
812 return s; | |
813 } | |
814 | |
815 @Override public LuanTable table() { | |
816 LuanTable tbl = super.table(); | |
817 try { | |
818 tbl.rawPut( "wait_for", new LuanJavaFunction( | |
819 LuanOs.class.getMethod( "wait_for" ), this | |
820 ) ); | |
821 } catch(NoSuchMethodException e) { | |
822 throw new RuntimeException(e); | |
823 } | |
824 return tbl; | |
825 } | |
826 } | |
827 | |
828 public static LuanTable os(LuanState luan,String cmd,LuanTable options) throws IOException, LuanException { | |
829 return new LuanOs(luan,cmd,options).table(); | |
830 } | |
831 | |
832 | |
833 public static String ip(String domain) { | |
834 try { | |
835 return InetAddress.getByName(domain).getHostAddress(); | |
836 } catch(UnknownHostException e) { | |
837 return null; | |
838 } | |
839 } | |
840 | |
841 public static LuanTable my_ips() throws IOException { | |
842 LuanTable tbl = new LuanTable(); | |
843 for( Enumeration<NetworkInterface> e1 = NetworkInterface.getNetworkInterfaces(); e1.hasMoreElements(); ) { | |
844 NetworkInterface ni = e1.nextElement(); | |
845 for( Enumeration<InetAddress> e2 = ni.getInetAddresses(); e2.hasMoreElements(); ) { | |
846 InetAddress ia = e2.nextElement(); | |
847 if( ia instanceof Inet4Address ) | |
848 tbl.rawPut(ia.getHostAddress(),true); | |
849 } | |
850 } | |
851 return tbl; | |
852 } | |
853 | |
854 /* | |
855 // files maps zip name to uri | |
856 public static void zip(LuanState luan,String zipUri,LuanTable files) throws LuanException, IOException { | |
857 Object obj = uri(luan,zipUri,null).rawGet("java"); | |
858 if( !(obj instanceof LuanIO) ) | |
859 throw new LuanException("invalid uri for zip"); | |
860 LuanIO zipIo = (LuanIO)obj; | |
861 ZipOutputStream out = new ZipOutputStream(zipIo.outputStream()); | |
862 for( Map.Entry<Object,Object> entry : files.iterable(luan) ) { | |
863 obj = entry.getKey(); | |
864 if( !(obj instanceof String) ) | |
865 throw new LuanException("zip file table keys must be strings"); | |
866 String fileName = (String)obj; | |
867 obj = entry.getValue(); | |
868 if( !(obj instanceof String) ) | |
869 throw new LuanException("zip file table values must be strings"); | |
870 String uriStr = (String)obj; | |
871 out.putNextEntry(new ZipEntry(fileName)); | |
872 obj = uri(luan,uriStr,null).rawGet("java"); | |
873 if( !(obj instanceof LuanIn) ) | |
874 throw new LuanException("invalid uri for zip"); | |
875 LuanIn zipIn = (LuanIn)obj; | |
876 InputStream in = zipIn.inputStream(); | |
877 Utils.copyAll(in,out); | |
878 in.close(); | |
879 out.closeEntry(); | |
880 } | |
881 out.close(); | |
882 } | |
883 */ | |
884 | |
885 // security | |
886 | |
887 public interface Security { | |
888 public void check(LuanState luan,String name) throws LuanException; | |
889 } | |
890 | |
891 private static String SECURITY_KEY = "Io.Security"; | |
892 | |
893 private static void check(LuanState luan,String name) throws LuanException { | |
894 Security s = (Security)luan.registry().get(SECURITY_KEY); | |
895 if( s!=null ) | |
896 s.check(luan,name); | |
897 } | |
898 | |
899 public static void setSecurity(LuanState luan,Security s) { | |
900 luan.registry().put(SECURITY_KEY,s); | |
901 } | |
902 | |
903 private void IoLuan() {} // never | |
904 } |