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 }