comparison core/src/luan/modules/RpcLuan.java @ 610:b4f3dbe1c6e3

add Rpc and change Hosting to use Rpc
author Franklin Schmidt <fschmidt@gmail.com>
date Fri, 11 Dec 2015 00:13:13 -0700
parents
children cdc70de628b5
comparison
equal deleted inserted replaced
609:24b05963ba62 610:b4f3dbe1c6e3
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.IOException;
8 import java.io.EOFException;
9 import java.nio.charset.StandardCharsets;
10 import java.util.Set;
11 import java.util.IdentityHashMap;
12 import java.util.Collections;
13 import java.util.Map;
14 import luan.Luan;
15 import luan.LuanState;
16 import luan.LuanTable;
17 import luan.LuanFunction;
18 import luan.LuanException;
19 import luan.LuanMethod;
20
21
22 public final class RpcLuan {
23 private static final int NIL = 0;
24 private static final int STRING = 1;
25 private static final int BOOLEAN = 2;
26 private static final int NUMBER = 3;
27 private static final int BINARY = 4;
28 private static final int TABLE = 5;
29
30 @LuanMethod public static Object[] call(LuanState luan,LuanTable socketTbl,String fnName,Object... args)
31 throws LuanException, IOException
32 {
33 IoLuan.LuanSocket socket = (IoLuan.LuanSocket)socketTbl.rawGet("java");
34 InputStream in = new BufferedInputStream(socket.inputStream());
35 OutputStream out = new BufferedOutputStream(socket.outputStream());
36 try {
37 writeString(out,fnName);
38 writeInt(out,args.length);
39 for( Object arg : args ) {
40 writeObj(out,luan,arg);
41 }
42 out.flush();
43 boolean ok = readBoolean(in);
44 if( ok ) {
45 int n = readInt(in);
46 Object[] rtn = new Object[n];
47 for( int i=0; i<n; i++ ) {
48 rtn[i] = readObj(in,luan);
49 }
50 return rtn;
51 } else {
52 String msg = readString(in);
53 throw new LuanException(luan,msg);
54 }
55 } finally {
56 out.close();
57 in.close();
58 }
59 }
60
61 public static void respond(LuanState luan,LuanTable socketTbl,LuanTable fns)
62 throws IOException, LuanException
63 {
64 IoLuan.LuanSocket socket = (IoLuan.LuanSocket)socketTbl.rawGet("java");
65 InputStream in = new BufferedInputStream(socket.inputStream());
66 OutputStream out = new BufferedOutputStream(socket.outputStream());
67 try {
68 Object[] rtn;
69 try {
70 String fnName = readString(in);
71 int nArgs = readInt(in);
72 Object[] args = new Object[nArgs];
73 for( int i=0; i<nArgs; i++ ) {
74 args[i] = readObj(in,luan);
75 }
76 LuanFunction fn = (LuanFunction)fns.rawGet(fnName);
77 if( fn == null )
78 throw new LuanException(luan, "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 return;
84 }
85 writeBoolean(out,true);
86 writeInt(out,rtn.length);
87 for( Object obj : rtn ) {
88 writeObj(out,luan,obj);
89 }
90 } finally {
91 out.close();
92 in.close();
93 }
94 }
95
96 static void writeObj(OutputStream out,LuanState luan,Object obj) throws IOException, LuanException {
97 if( obj == null ) {
98 out.write(NIL);
99 }
100 else if( obj instanceof String ) {
101 out.write(STRING);
102 writeString(out,(String)obj);
103 }
104 else if( obj instanceof Boolean ) {
105 out.write(BOOLEAN);
106 writeBoolean(out,(Boolean)obj);
107 }
108 else if( obj instanceof Number ) {
109 out.write(NUMBER);
110 writeString(out,obj.toString());
111 }
112 else if( obj instanceof byte[] ) {
113 byte[] a = (byte[])obj;
114 out.write(BINARY);
115 writeInt(out,a.length);
116 out.write(a);
117 }
118 else if( obj instanceof LuanTable ) {
119 out.write(TABLE);
120 String s = pickle( luan, obj, Collections.newSetFromMap(new IdentityHashMap<LuanTable,Boolean>()) );
121 writeString(out,s);
122 }
123 else
124 throw new LuanException(luan, "invalid type: " + obj.getClass() );
125 }
126
127 static Object readObj(InputStream in,LuanState luan) throws IOException, LuanException {
128 int type = in.read();
129 switch(type) {
130 case NIL:
131 return null;
132 case STRING:
133 return readString(in);
134 case BOOLEAN:
135 return readBoolean(in);
136 case NUMBER:
137 return Double.valueOf(readString(in));
138 case BINARY:
139 return readBinary(in,readInt(in));
140 case TABLE:
141 String s = readString(in);
142 LuanFunction fn = BasicLuan.load(luan,s,"rpc-reader",null,true);
143 return fn.call(luan);
144 default:
145 throw new LuanException(luan, "invalid type: " + type );
146 }
147 }
148
149 static Boolean readBoolean(InputStream in) throws IOException {
150 return Boolean.valueOf(readString(in));
151 }
152
153 static String readString(InputStream in) throws IOException {
154 int len = readInt(in);
155 byte[] a = readBinary(in,len);
156 return new String(a,StandardCharsets.UTF_8);
157 }
158
159 static int readInt(InputStream in) throws IOException {
160 int ch1 = in.read();
161 int ch2 = in.read();
162 int ch3 = in.read();
163 int ch4 = in.read();
164 if ((ch1 | ch2 | ch3 | ch4) < 0)
165 throw new EOFException();
166 return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
167 }
168
169 static byte[] readBinary(InputStream in,int size) throws IOException {
170 byte[] a = new byte[size];
171 int i = 0;
172 while( i < size ) {
173 int n = in.read(a,i,size-i);
174 if( n == -1 )
175 throw new EOFException();
176 i += n;
177 }
178 return a;
179 }
180
181 static void writeBoolean(OutputStream out,Boolean b) throws IOException {
182 writeString(out,b.toString());
183 }
184
185 static void writeString(OutputStream out,String s) throws IOException {
186 byte[] a = s.getBytes(StandardCharsets.UTF_8);
187 writeInt(out,a.length);
188 out.write(a);
189 }
190
191 static void writeInt(OutputStream out,int v) throws IOException {
192 out.write((v >>> 24) & 0xFF);
193 out.write((v >>> 16) & 0xFF);
194 out.write((v >>> 8) & 0xFF);
195 out.write((v >>> 0) & 0xFF);
196 }
197
198
199 private static String pickle(LuanState luan,Object obj,Set<LuanTable> set) throws LuanException {
200 if( obj == null )
201 return "nil";
202 if( obj instanceof Boolean )
203 return obj.toString();
204 if( obj instanceof Number )
205 return Luan.toString((Number)obj);
206 if( obj instanceof String )
207 return "\"" + Luan.stringEncode((String)obj) + "\"";
208 if( obj instanceof LuanTable ) {
209 LuanTable tbl = (LuanTable)obj;
210 if( !set.add(tbl) ) {
211 throw new LuanException(luan, "circular reference in table" );
212 }
213 StringBuilder sb = new StringBuilder();
214 sb.append( "{" );
215 for( Map.Entry<Object,Object> entry : tbl.iterable(luan) ) {
216 sb.append( "[" );
217 sb.append( pickle(luan,entry.getKey(),set) );
218 sb.append( "]=" );
219 sb.append( pickle(luan,entry.getValue(),set) );
220 sb.append( ", " );
221 }
222 sb.append( "}" );
223 return sb.toString();
224 }
225 throw new LuanException(luan, "invalid type: " + obj.getClass() );
226 }
227
228 }