Mercurial Hosting > luan
comparison src/luan/modules/RpcLuan.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/RpcLuan.java@ae612dfc57cb |
children | 88b5b81cad4a |
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.BufferedInputStream; | |
6 import java.io.BufferedOutputStream; | |
7 import java.io.InputStreamReader; | |
8 import java.io.FilterInputStream; | |
9 import java.io.IOException; | |
10 import java.io.EOFException; | |
11 import java.net.Socket; | |
12 import java.nio.charset.StandardCharsets; | |
13 import java.util.Set; | |
14 import java.util.IdentityHashMap; | |
15 import java.util.Collections; | |
16 import java.util.Map; | |
17 import luan.Luan; | |
18 import luan.LuanState; | |
19 import luan.LuanTable; | |
20 import luan.LuanFunction; | |
21 import luan.LuanException; | |
22 import luan.LuanMethod; | |
23 import luan.modules.parsers.Json; | |
24 import luan.modules.parsers.ParseException; | |
25 | |
26 | |
27 public final class RpcLuan { | |
28 private static final int NIL = 0; | |
29 private static final int STRING = 1; | |
30 private static final int BOOLEAN = 2; | |
31 private static final int NUMBER = 3; | |
32 private static final int BINARY = 4; | |
33 private static final int TABLE = 5; | |
34 private static final int IO = 6; | |
35 private static final int LONG = 7; | |
36 | |
37 @LuanMethod public static Object[] call(LuanState luan,LuanTable socketTbl,String fnName,Object... args) | |
38 throws LuanException, IOException | |
39 { | |
40 IoLuan.LuanSocket luanSocket = (IoLuan.LuanSocket)socketTbl.rawGet("java"); | |
41 Socket socket = luanSocket.socket; | |
42 InputStream in = new BufferedInputStream(socket.getInputStream()); | |
43 OutputStream out = new BufferedOutputStream(socket.getOutputStream()); | |
44 Close close = new Close(); | |
45 try { | |
46 writeString(out,fnName); | |
47 writeObjs(out,luan,args); | |
48 out.flush(); | |
49 socket.shutdownOutput(); | |
50 boolean ok = readBoolean(in); | |
51 if( ok ) { | |
52 return readObjs(in,luan,close); | |
53 } else { | |
54 String msg = readString(in); | |
55 throw new LuanException(msg); | |
56 } | |
57 } finally { | |
58 if( close.b) { | |
59 socket.close(); | |
60 } | |
61 } | |
62 } | |
63 | |
64 public static void respond(LuanState luan,LuanTable socketTbl,LuanTable fns) | |
65 throws IOException, LuanException | |
66 { | |
67 IoLuan.LuanSocket luanSocket = (IoLuan.LuanSocket)socketTbl.rawGet("java"); | |
68 Socket socket = luanSocket.socket; | |
69 InputStream in = new BufferedInputStream(socket.getInputStream()); | |
70 OutputStream out = new BufferedOutputStream(socket.getOutputStream()); | |
71 try { | |
72 Object[] rtn; | |
73 try { | |
74 String fnName = readString(in); | |
75 Object[] args = readObjs(in,luan,null); | |
76 LuanFunction fn = (LuanFunction)fns.get(luan,fnName); | |
77 if( fn == null ) | |
78 throw new LuanException( "function not found: " + fnName ); | |
79 rtn = Luan.array(fn.call(luan,args)); | |
80 } catch(LuanException e) { | |
81 writeBoolean(out,false); | |
82 writeString(out,e.getFullMessage()); | |
83 out.flush(); | |
84 return; | |
85 } | |
86 writeBoolean(out,true); | |
87 writeObjs(out,luan,rtn); | |
88 out.flush(); | |
89 } finally { | |
90 socket.close(); | |
91 } | |
92 } | |
93 | |
94 private static void writeObjs(OutputStream out,LuanState luan,Object[] a) throws IOException, LuanException { | |
95 IoLuan.LuanIn luanIn = null; | |
96 writeInt(out,a.length); | |
97 for( Object obj : a ) { | |
98 if( obj instanceof LuanTable ) { | |
99 LuanTable tbl = (LuanTable)obj; | |
100 Object java = tbl.rawGet("java"); | |
101 if( java instanceof IoLuan.LuanIn ) { | |
102 if( luanIn != null ) | |
103 throw new LuanException("can't have multiple IO params"); | |
104 luanIn = (IoLuan.LuanIn)java; | |
105 out.write(IO); | |
106 continue; | |
107 } | |
108 } | |
109 writeObj(out,luan,obj); | |
110 } | |
111 if( luanIn != null ) { | |
112 InputStream in = luanIn.inputStream(); | |
113 Utils.copyAll(in,out); | |
114 } | |
115 } | |
116 | |
117 private static Object[] readObjs(InputStream in,LuanState luan,Close close) throws IOException, LuanException { | |
118 int n = readInt(in); | |
119 Object[] rtn = new Object[n]; | |
120 for( int i=0; i<n; i++ ) { | |
121 rtn[i] = readObj(in,luan,close); | |
122 } | |
123 return rtn; | |
124 } | |
125 | |
126 private static void writeObj(OutputStream out,LuanState luan,Object obj) throws IOException, LuanException { | |
127 if( obj == null ) { | |
128 out.write(NIL); | |
129 } | |
130 else if( obj instanceof String ) { | |
131 out.write(STRING); | |
132 writeString(out,(String)obj); | |
133 } | |
134 else if( obj instanceof Boolean ) { | |
135 out.write(BOOLEAN); | |
136 writeBoolean(out,(Boolean)obj); | |
137 } | |
138 else if( obj instanceof Long ) { | |
139 out.write(LONG); | |
140 writeString(out,obj.toString()); | |
141 } | |
142 else if( obj instanceof Number ) { | |
143 out.write(NUMBER); | |
144 writeString(out,obj.toString()); | |
145 } | |
146 else if( obj instanceof byte[] ) { | |
147 byte[] a = (byte[])obj; | |
148 out.write(BINARY); | |
149 writeInt(out,a.length); | |
150 out.write(a); | |
151 } | |
152 else if( obj instanceof LuanTable ) { | |
153 out.write(TABLE); | |
154 // String s = pickle( luan, obj, Collections.newSetFromMap(new IdentityHashMap<LuanTable,Boolean>()) ); | |
155 String s = Json.toString(obj); | |
156 writeString(out,s); | |
157 } | |
158 else | |
159 throw new LuanException( "invalid type: " + obj.getClass() ); | |
160 } | |
161 | |
162 private static Object readObj(InputStream in,LuanState luan,Close close) throws IOException, LuanException { | |
163 int type = in.read(); | |
164 switch(type) { | |
165 case NIL: | |
166 return null; | |
167 case STRING: | |
168 return readString(in); | |
169 case BOOLEAN: | |
170 return readBoolean(in); | |
171 case LONG: | |
172 return Long.valueOf(readString(in)); | |
173 case NUMBER: | |
174 return Double.valueOf(readString(in)); | |
175 case BINARY: | |
176 return readBinary(in,readInt(in)); | |
177 case TABLE: | |
178 String s = readString(in); | |
179 /* | |
180 LuanFunction fn = Luan.load("return "+s,"rpc-reader"); | |
181 return fn.call(luan); | |
182 */ | |
183 try { | |
184 return Json.parse(s); | |
185 } catch(ParseException e) { | |
186 throw new LuanException(e); | |
187 } | |
188 case IO: | |
189 return new LuanInputStream(in,close).table(); | |
190 default: | |
191 throw new LuanException( "invalid type: " + type ); | |
192 } | |
193 } | |
194 | |
195 private static Boolean readBoolean(InputStream in) throws IOException { | |
196 return Boolean.valueOf(readString(in)); | |
197 } | |
198 | |
199 private static String readString(InputStream in) throws IOException { | |
200 int len = readInt(in); | |
201 byte[] a = readBinary(in,len); | |
202 return new String(a,StandardCharsets.UTF_8); | |
203 } | |
204 | |
205 private static int readInt(InputStream in) throws IOException { | |
206 int ch1 = in.read(); | |
207 int ch2 = in.read(); | |
208 int ch3 = in.read(); | |
209 int ch4 = in.read(); | |
210 if ((ch1 | ch2 | ch3 | ch4) < 0) | |
211 throw new EOFException(); | |
212 return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0)); | |
213 } | |
214 | |
215 private static byte[] readBinary(InputStream in,int size) throws IOException { | |
216 byte[] a = new byte[size]; | |
217 int i = 0; | |
218 while( i < size ) { | |
219 int n = in.read(a,i,size-i); | |
220 if( n == -1 ) | |
221 throw new EOFException(); | |
222 i += n; | |
223 } | |
224 return a; | |
225 } | |
226 | |
227 private static void writeBoolean(OutputStream out,Boolean b) throws IOException { | |
228 writeString(out,b.toString()); | |
229 } | |
230 | |
231 private static void writeString(OutputStream out,String s) throws IOException { | |
232 byte[] a = s.getBytes(StandardCharsets.UTF_8); | |
233 writeInt(out,a.length); | |
234 out.write(a); | |
235 } | |
236 | |
237 private static void writeInt(OutputStream out,int v) throws IOException { | |
238 out.write((v >>> 24) & 0xFF); | |
239 out.write((v >>> 16) & 0xFF); | |
240 out.write((v >>> 8) & 0xFF); | |
241 out.write((v >>> 0) & 0xFF); | |
242 } | |
243 | |
244 /* | |
245 private static String pickle(LuanState luan,Object obj,Set<LuanTable> set) throws LuanException { | |
246 if( obj == null ) | |
247 return "nil"; | |
248 if( obj instanceof Boolean ) | |
249 return obj.toString(); | |
250 if( obj instanceof Number ) | |
251 return Luan.toString((Number)obj); | |
252 if( obj instanceof String ) | |
253 return "\"" + Luan.stringEncode((String)obj) + "\""; | |
254 if( obj instanceof LuanTable ) { | |
255 LuanTable tbl = (LuanTable)obj; | |
256 if( !set.add(tbl) ) { | |
257 throw new LuanException( "circular reference in table" ); | |
258 } | |
259 StringBuilder sb = new StringBuilder(); | |
260 sb.append( "{" ); | |
261 for( Map.Entry<Object,Object> entry : tbl.iterable(luan) ) { | |
262 sb.append( "[" ); | |
263 sb.append( pickle(luan,entry.getKey(),set) ); | |
264 sb.append( "]=" ); | |
265 sb.append( pickle(luan,entry.getValue(),set) ); | |
266 sb.append( ", " ); | |
267 } | |
268 sb.append( "}" ); | |
269 return sb.toString(); | |
270 } | |
271 throw new LuanException( "invalid type: " + obj.getClass() ); | |
272 } | |
273 */ | |
274 | |
275 private static class Close { | |
276 boolean b = true; | |
277 } | |
278 | |
279 private static class LuanInputStream extends IoLuan.LuanIn { | |
280 private final InputStream in; | |
281 private final boolean close; | |
282 | |
283 public LuanInputStream(InputStream in,Close close) { | |
284 this.in = in; | |
285 this.close = close!=null && close.b; | |
286 if(this.close) close.b = false; | |
287 } | |
288 | |
289 @Override public InputStream inputStream() { | |
290 return new FilterInputStream(in) { | |
291 @Override public void close() throws IOException { | |
292 if(close) super.close(); | |
293 } | |
294 }; | |
295 } | |
296 | |
297 @Override public String to_string() { | |
298 return "<input_stream>"; | |
299 } | |
300 | |
301 @Override public String to_uri_string() { | |
302 throw new UnsupportedOperationException(); | |
303 } | |
304 | |
305 @Override public boolean exists() { | |
306 return true; | |
307 } | |
308 }; | |
309 | |
310 } |