Files
websocket-driver-ruby/ext/websocket_driver/WebsocketDriverService.java
T

173 lines
6.1 KiB
Java

import java.io.IOException;
import com.jcoglan.websocket.Extensions;
import com.jcoglan.websocket.Frame;
import com.jcoglan.websocket.Message;
import com.jcoglan.websocket.Observer;
import com.jcoglan.websocket.Parser;
import com.jcoglan.websocket.Unparser;
import org.jruby.Ruby;
import org.jruby.RubyArray;
import org.jruby.RubyBoolean;
import org.jruby.RubyClass;
import org.jruby.RubyFixnum;
import org.jruby.RubyModule;
import org.jruby.RubyObject;
import org.jruby.RubyString;
import org.jruby.RubySymbol;
import org.jruby.anno.JRubyMethod;
import org.jruby.runtime.ObjectAllocator;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.load.BasicLibraryService;
public class WebsocketDriverService implements BasicLibraryService {
private Ruby runtime;
public boolean basicLoad(Ruby runtime) throws IOException {
this.runtime = runtime;
RubyModule websocket = runtime.defineModule("WebSocketNative");
RubyClass parser = websocket.defineClassUnder("Parser", runtime.getObject(), new ObjectAllocator() {
public IRubyObject allocate(Ruby runtime, RubyClass rubyClass) {
return new RParser(runtime, rubyClass);
}
});
parser.defineAnnotatedMethods(RParser.class);
RubyClass unparser = websocket.defineClassUnder("Unparser", runtime.getObject(), new ObjectAllocator() {
public IRubyObject allocate(Ruby runtime, RubyClass rubyClass) {
return new RUnparser(runtime, rubyClass);
}
});
unparser.defineAnnotatedMethods(RUnparser.class);
return true;
}
public class RParser extends RubyObject {
private Parser parser;
private R r;
public RParser(final Ruby runtime, RubyClass rubyClass) {
super(runtime, rubyClass);
this.r = new R(runtime);
}
@JRubyMethod
public IRubyObject initialize(final ThreadContext context, final IRubyObject driver, IRubyObject requireMasking) {
Extensions extensions = new Extensions() {
public boolean validFrameRsv(boolean rsv1, boolean rsv2, boolean rsv3, int opcode) {
IRubyObject[] args = {r.symbol("valid_frame_rsv?"), r.bool(rsv1), r.bool(rsv2), r.bool(rsv3), r.fixnum(opcode)};
return ((RubyObject)driver).send(context, args, null).isTrue();
}
};
Observer observer = new Observer() {
public void onError(int code, String reason) {
IRubyObject[] args = {r.symbol("handle_error"), r.fixnum(code), r.string(reason.getBytes())};
((RubyObject)driver).send(context, args, null);
}
public void onMessage(Message message) {
IRubyObject[] args = {
r.symbol("handle_message"),
r.fixnum(message.opcode),
r.bool(message.rsv1),
r.bool(message.rsv2),
r.bool(message.rsv3),
r.string(message.copy())
};
((RubyObject)driver).send(context, args, null);
}
public void onClose(int code, byte[] reason) {
IRubyObject[] args = {r.symbol("handle_close"), r.fixnum(code), r.string(reason)};
((RubyObject)driver).send(context, args, null);
}
public void onPing(Frame frame) {
IRubyObject[] args = {r.symbol("handle_ping"), r.string(frame.payload)};
((RubyObject)driver).send(context, args, null);
}
public void onPong(Frame frame) {
IRubyObject[] args = {r.symbol("handle_pong"), r.string(frame.payload)};
((RubyObject)driver).send(context, args, null);
}
};
parser = new Parser(extensions, observer, requireMasking.isTrue());
return null;
}
@JRubyMethod
public IRubyObject parse(IRubyObject chunk) {
byte[] bytes = ((RubyString)chunk).getBytes();
parser.parse(bytes);
return null;
}
}
public class RUnparser extends RubyObject {
private Unparser unparser;
private R r;
public RUnparser(Ruby runtime, RubyClass rubyClass) {
super(runtime, rubyClass);
this.r = new R(runtime);
}
@JRubyMethod
public IRubyObject initialize(IRubyObject driver, IRubyObject masking) {
unparser = new Unparser(masking.isTrue());
return null;
}
@JRubyMethod
public IRubyObject frame(IRubyObject head, IRubyObject maskingKey, IRubyObject payload) {
byte[] buffer = ((RubyString)payload).getBytes();
RubyArray args = (RubyArray)head;
Frame frame = new Frame();
frame.fin = (Boolean)args.get(0);
frame.rsv1 = (Boolean)args.get(1);
frame.rsv2 = (Boolean)args.get(2);
frame.rsv3 = (Boolean)args.get(3);
frame.opcode = ((Long)args.get(4)).intValue();
frame.length = buffer.length;
frame.maskingKey = ((RubyString)maskingKey).getBytes();
frame.payload = ((RubyString)payload).getBytes();
byte[] result = unparser.frame(frame);
return r.string(result);
}
}
class R {
private Ruby runtime;
R(Ruby runtime) {
this.runtime = runtime;
}
RubyBoolean bool(boolean value) {
return RubyBoolean.newBoolean(runtime, value);
}
RubyFixnum fixnum(int value) {
return RubyFixnum.newFixnum(runtime, value);
}
RubySymbol symbol(String name) {
return RubySymbol.newSymbol(runtime, name);
}
RubyString string(byte[] value) {
return new RubyString(runtime, RubyString.createStringClass(runtime), value);
}
}
}