Mercurial Hosting > luan
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 } |