//export ReadMsgpackFrame // // ReadMsgpackFrame reads the msgpack frame at byteOffset in rawStream, decodes the // 2-5 bytes of a msgpack binary array (either bin8, bin16, or bin32), and returns // and the decoded-into-R object and the next byteOffset to use. // func ReadMsgpackFrame(rawStream C.SEXP, byteOffset C.SEXP) C.SEXP { var start int if C.TYPEOF(byteOffset) == C.REALSXP { start = int(C.get_real_elt(byteOffset, 0)) } else if C.TYPEOF(byteOffset) == C.INTSXP { start = int(C.get_int_elt(byteOffset, 0)) } else { C.ReportErrorToR_NoReturn(C.CString("read.msgpack.frame(x, byteOffset) requires byteOffset to be a numeric byte-offset number.")) } // rawStream must be a RAWSXP if C.TYPEOF(rawStream) != C.RAWSXP { C.ReportErrorToR_NoReturn(C.CString("read.msgpack.frame(x, byteOffset) requires x be a RAW vector of bytes.")) } n := int(C.Rf_xlength(rawStream)) if n == 0 { return C.R_NilValue } if start >= n { C.ReportErrorToR_NoReturn(C.CString(fmt.Sprintf("read.msgpack.frame(x, byteOffset) error: byteOffset(%d) is beyond the length of x (x has len %d).", start, n))) } var decoder [5]byte C.memcpy(unsafe.Pointer(&decoder[0]), unsafe.Pointer(C.get_raw_elt_ptr(rawStream, C.ulonglong(start))), C.size_t(5)) headerSz, _, totalSz, err := DecodeMsgpackBinArrayHeader(decoder[:]) if err != nil { C.ReportErrorToR_NoReturn(C.CString(fmt.Sprintf("ReadMsgpackFrame error trying to decode msgpack frame: %s", err))) } if start+totalSz > n { C.ReportErrorToR_NoReturn(C.CString(fmt.Sprintf("read.msgpack.frame(x, byteOffset) error: byteOffset(%d) plus the frames size(%d) goes beyond the length of x (x has len %d).", start, totalSz, n))) } bytes := make([]byte, totalSz) C.memcpy(unsafe.Pointer(&bytes[0]), unsafe.Pointer(C.get_raw_elt_ptr(rawStream, C.ulonglong(start))), C.size_t(totalSz)) rObject := decodeMsgpackToR(bytes[headerSz:]) C.Rf_protect(rObject) returnList := C.allocVector(C.VECSXP, C.R_xlen_t(2)) C.Rf_protect(returnList) C.SET_VECTOR_ELT(returnList, C.R_xlen_t(0), C.Rf_ScalarReal(C.double(float64(start+totalSz)))) C.SET_VECTOR_ELT(returnList, C.R_xlen_t(1), rObject) C.Rf_unprotect_ptr(rObject) C.Rf_unprotect_ptr(returnList) return returnList }
//export Cli func Cli(str_ C.SEXP) C.SEXP { if C.TYPEOF(str_) != C.STRSXP { fmt.Printf("not a STRXSP! instead: %d, argument to rmq() must be a string to be decoded to its integer constant value in the rmq pkg.\n", C.TYPEOF(str_)) return C.R_NilValue } name := C.R_CHAR(C.STRING_ELT(str_, 0)) msg := C.GoString(name) //fmt.Printf("rmq says: client sees '%s'.\n", msg) reply := client_main([]byte(msg)) VPrintf("rmq says: after client_main().\n") if len(reply) == 0 { return C.R_NilValue } if len(reply) > 0 { return decodeMsgpackToR(reply) } return C.R_NilValue }
func getTimeoutMsec(timeout_msec_ C.SEXP) (int, error) { if C.TYPEOF(timeout_msec_) != C.REALSXP || int(C.Rf_xlength(timeout_msec_)) != 1 { return 0, fmt.Errorf("getTimeoutMsec() error: timeout_msec must be a single number; it should convey the number of milliseconds to wait before timing out the call.") } return int(C.get_real_elt(timeout_msec_, 0)), nil }
//export ReadNewlineDelimJson // // ReadNewlineDelimJson reads a json object at byteOffset in rawStream, expects // it to be newline terminated, and returns the // decoded-into-R object and the next byteOffset to use (the byte just after // the terminating newline). // func ReadNewlineDelimJson(rawStream C.SEXP, byteOffset C.SEXP) C.SEXP { C.Rf_protect(rawStream) var start int if C.TYPEOF(byteOffset) == C.REALSXP { start = int(C.get_real_elt(byteOffset, 0)) } else if C.TYPEOF(byteOffset) == C.INTSXP { start = int(C.get_int_elt(byteOffset, 0)) } else { C.ReportErrorToR_NoReturn(C.CString("read.ndjson(x, byteOffset) requires byteOffset to be a numeric byte-offset number.")) } // rawStream must be a RAWSXP if C.TYPEOF(rawStream) != C.RAWSXP { C.ReportErrorToR_NoReturn(C.CString("read.ndjson(x, byteOffset) requires x be a RAW vector of bytes.")) } n := int(C.Rf_xlength(rawStream)) if n == 0 { return C.R_NilValue } if start >= n { C.ReportErrorToR_NoReturn(C.CString(fmt.Sprintf("read.ndjson(x, byteOffset) error: byteOffset(%d) is at or beyond the length of x (x has len %d).", start, n))) } // INVAR: start < n // find the next newline or end of raw array next := int(C.next_newline_pos(rawStream, C.ulonglong(start+1), C.ulonglong(n))) totalSz := next - start bytes := make([]byte, totalSz) fromPtr := unsafe.Pointer(C.get_raw_elt_ptr(rawStream, C.ulonglong(start))) C.memcpy(unsafe.Pointer(&bytes[0]), fromPtr, C.size_t(totalSz)) rObject := decodeJsonToR(bytes) C.Rf_protect(rObject) returnList := C.allocVector(C.VECSXP, C.R_xlen_t(2)) C.Rf_protect(returnList) C.SET_VECTOR_ELT(returnList, C.R_xlen_t(0), C.Rf_ScalarReal(C.double(float64(start+totalSz)))) C.SET_VECTOR_ELT(returnList, C.R_xlen_t(1), rObject) C.Rf_unprotect_ptr(rObject) C.Rf_unprotect_ptr(returnList) C.Rf_unprotect_ptr(rawStream) return returnList }
func getAddr(addr_ C.SEXP) (*net.TCPAddr, error) { if C.TYPEOF(addr_) != C.STRSXP { return nil, fmt.Errorf("getAddr() error: addr is not a string STRXSP; instead it is type %d. addr argument must be a string of form 'ip:port'\n", C.TYPEOF(addr_)) } caddr := C.R_CHAR(C.STRING_ELT(addr_, 0)) addr := C.GoString(caddr) tcpAddr, err := net.ResolveTCPAddr("tcp", addr) if err != nil || tcpAddr == nil { return nil, fmt.Errorf("getAddr() error: address '%s' could not be parsed by net.ResolveTCPAddr(): error: '%s'", addr, err) } return tcpAddr, nil }
//export FromMsgpack func FromMsgpack(s C.SEXP) C.SEXP { // starting from within R, we convert a raw byte vector into R structures. // s must be a RAWSXP if C.TYPEOF(s) != C.RAWSXP { C.ReportErrorToR_NoReturn(C.CString("from.msgpack(x) requires x be a RAW vector of bytes.")) } n := int(C.Rf_xlength(s)) if n == 0 { return C.R_NilValue } bytes := make([]byte, n) C.memcpy(unsafe.Pointer(&bytes[0]), unsafe.Pointer(C.RAW(s)), C.size_t(n)) return decodeMsgpackToR(bytes) }
//export Srv func Srv(str_ C.SEXP) C.SEXP { if C.TYPEOF(str_) != C.STRSXP { fmt.Printf("not a STRXSP! instead: %d, argument to rmq() must be a string to be decoded to its integer constant value in the rmq pkg.\n", C.TYPEOF(str_)) return C.R_NilValue } name := C.R_CHAR(C.STRING_ELT(str_, 0)) gname := C.GoString(name) fmt.Printf("rmq says: Hello '%s'!\n", gname) //go StartServer() go server_main() fmt.Printf("\n after gorilla webserver on '%s' launched.\n", addr) return C.R_NilValue }
//export ReadTmFrame // // ReadTmFrame reads a TMFRAME file and returns the frames as // an R dataframe. // func ReadTmFrame(path_ C.SEXP) C.SEXP { // s must be a RAWSXP if C.TYPEOF(path_) != C.STRSXP { C.ReportErrorToR_NoReturn(C.CString("ReadTmFrame() error: path is not a string path to TMFRAME file.")) } cpath := C.R_CHAR(C.STRING_ELT(path_, 0)) path := C.GoString(cpath) if !FileExists(path) { C.ReportErrorToR_NoReturn(C.CString(fmt.Sprintf("ReadTmFrame() error: bad path '%s'; does not exist", path))) } /// begin TMFRAME read f, err := os.Open(path) if err != nil { C.ReportErrorToR_NoReturn(C.CString(fmt.Sprintf("ReadTmFrame() error, could not open path '%s': '%s'", path, err))) } i := int64(1) fr := tf.NewFrameReader(f, 1024*1024) var frame *tf.Frame //var raw []byte res := []*tf.Frame{} toploop: for ; err == nil; i++ { frame, _, err, _ = fr.NextFrame(nil) if err != nil { if err == io.EOF { break toploop } C.ReportErrorToR_NoReturn(C.CString(fmt.Sprintf("ReadTmFrame() error reading '%s', fr.NextFrame() at i=%v gave error: '%v'", path, i, err))) } res = append(res, frame) } // end for toploop if len(res) > 0 { return tmFramesToR(res) } return C.R_NilValue }
func toIface(s C.SEXP) interface{} { // generate a go map or slice or scalar value, then encode it n := int(C.Rf_xlength(s)) if n == 0 { return nil // drops type info. Meh. } switch C.TYPEOF(s) { case C.VECSXP: // an R generic vector; e.g list() VPrintf("encodeRIntoMsgpack sees VECSXP\n") // could be a map or a slice. Check out the names. rnames := C.Rf_getAttrib(s, C.R_NamesSymbol) rnamesLen := int(C.Rf_xlength(rnames)) VPrintf("namesLen = %d\n", rnamesLen) if rnamesLen > 0 { myMap := map[string]interface{}{} for i := 0; i < rnamesLen; i++ { myMap[C.GoString(C.get_string_elt(rnames, C.int(i)))] = toIface(C.VECTOR_ELT(s, C.R_xlen_t(i))) } VPrintf("VECSXP myMap = '%#v'\n", myMap) return myMap } else { // else: no names, so we treat it as an array instead of as a map mySlice := make([]interface{}, n) for i := 0; i < n; i++ { mySlice[i] = toIface(C.VECTOR_ELT(s, C.R_xlen_t(i))) } VPrintf("VECSXP mySlice = '%#v'\n", mySlice) return mySlice } case C.REALSXP: // a vector of float64 (numeric) VPrintf("encodeRIntoMsgpack sees REALSXP\n") mySlice := make([]float64, n) for i := 0; i < n; i++ { mySlice[i] = float64(C.get_real_elt(s, C.int(i))) } VPrintf("VECSXP mySlice = '%#v'\n", mySlice) return mySlice case C.INTSXP: // a vector of int32 VPrintf("encodeRIntoMsgpack sees INTSXP\n") mySlice := make([]int, n) for i := 0; i < n; i++ { mySlice[i] = int(C.get_int_elt(s, C.int(i))) } VPrintf("INTSXP mySlice = '%#v'\n", mySlice) return mySlice case C.RAWSXP: VPrintf("encodeRIntoMsgpack sees RAWSXP\n") mySlice := make([]byte, n) C.memcpy(unsafe.Pointer(&mySlice[0]), unsafe.Pointer(C.RAW(s)), C.size_t(n)) VPrintf("RAWSXP mySlice = '%#v'\n", mySlice) return mySlice case C.STRSXP: // a vector of string (pointers to charsxp that are interned) VPrintf("encodeRIntoMsgpack sees STRSXP\n") mySlice := make([]string, n) for i := 0; i < n; i++ { mySlice[i] = C.GoString(C.get_string_elt(s, C.int(i))) } VPrintf("STRSXP mySlice = '%#v'\n", mySlice) return mySlice case C.NILSXP: // c(); an empty vector VPrintf("encodeRIntoMsgpack sees NILSXP\n") return nil case C.CHARSXP: // a single string, interned in a global pool for reuse by STRSXP. VPrintf("encodeRIntoMsgpack sees CHARSXP\n") case C.SYMSXP: VPrintf("encodeRIntoMsgpack sees SYMSXP\n") case C.LISTSXP: VPrintf("encodeRIntoMsgpack sees LISTSXP\n") case C.CLOSXP: VPrintf("encodeRIntoMsgpack sees CLOSXP\n") case C.ENVSXP: VPrintf("encodeRIntoMsgpack sees ENVSXP\n") case C.PROMSXP: VPrintf("encodeRIntoMsgpack sees PROMSXP\n") case C.LANGSXP: VPrintf("encodeRIntoMsgpack sees LANGSXP\n") case C.SPECIALSXP: VPrintf("encodeRIntoMsgpack sees SPECIALSXP\n") case C.BUILTINSXP: VPrintf("encodeRIntoMsgpack sees BUILTINSXP\n") case C.LGLSXP: VPrintf("encodeRIntoMsgpack sees LGLSXP\n") case C.CPLXSXP: VPrintf("encodeRIntoMsgpack sees CPLXSXP\n") case C.DOTSXP: VPrintf("encodeRIntoMsgpack sees DOTSXP\n") case C.ANYSXP: VPrintf("encodeRIntoMsgpack sees ANYSXP\n") case C.EXPRSXP: VPrintf("encodeRIntoMsgpack sees EXPRSXP\n") case C.BCODESXP: VPrintf("encodeRIntoMsgpack sees BCODESXP\n") case C.EXTPTRSXP: VPrintf("encodeRIntoMsgpack sees EXTPTRSXP\n") case C.WEAKREFSXP: VPrintf("encodeRIntoMsgpack sees WEAKREFSXP\n") case C.S4SXP: VPrintf("encodeRIntoMsgpack sees S4SXP\n") default: VPrintf("encodeRIntoMsgpack sees <unknown>\n") } VPrintf("... warning: encodeRIntoMsgpack() ignoring this input.\n") return nil }
//export ListenAndServe func ListenAndServe(addr_ C.SEXP, handler_ C.SEXP, rho_ C.SEXP) C.SEXP { if C.TYPEOF(addr_) != C.STRSXP { fmt.Printf("addr is not a string (STRXSP; instead it is: %d)! addr argument to ListenAndServe() must be a string of form 'ip:port'\n", C.TYPEOF(addr_)) return C.R_NilValue } //msglen := 0 if 0 == int(C.isFunction(handler_)) { // 0 is false C.ReportErrorToR_NoReturn(C.CString("‘handler’ must be a function")) return C.R_NilValue } if rho_ != nil && rho_ != C.R_NilValue { if 0 == int(C.isEnvironment(rho_)) { // 0 is false C.ReportErrorToR_NoReturn(C.CString("‘rho’ should be an environment")) return C.R_NilValue } } caddr := C.R_CHAR(C.STRING_ELT(addr_, 0)) addr := C.GoString(caddr) fmt.Printf("ListenAndServe listening on address '%s'...\n", addr) webSockHandler := func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/" { http.Error(w, "Not found", 404) return } if r.Method != "GET" { http.Error(w, "Method not allowed, only GET allowed.", 405) return } c, err := upgrader.Upgrade(w, r, nil) if err != nil { fmt.Print("websocket handler upgrade error:", err) return } defer c.Close() mt, message, err := c.ReadMessage() if err != nil { fmt.Println("read error: ", err) return } // make the call, and get a response msglen := len(message) rawmsg := C.allocVector(C.RAWSXP, C.R_xlen_t(msglen)) C.Rf_protect(rawmsg) C.memcpy(unsafe.Pointer(C.RAW(rawmsg)), unsafe.Pointer(&message[0]), C.size_t(msglen)) // put msg into env that handler_ is called with. C.defineVar(C.install(C.CString("msg")), rawmsg, rho_) R_serialize_fun = C.findVar(C.install(C.CString("serialize")), C.R_GlobalEnv) // todo: callbacks to R functions here not working. don't really need them if R always acts as a client instead. // evaluate C.PrintToR(C.CString("listenAndServe: stuffed msg into env rho_.\n")) //R_fcall := C.lang3(handler_, rawmsg, C.R_NilValue) R_fcall := C.lang3(R_serialize_fun, rawmsg, C.R_NilValue) C.Rf_protect(R_fcall) C.PrintToR(C.CString("listenAndServe: got msg, just prior to eval.\n")) evalres := C.eval(R_fcall, rho_) C.Rf_protect(evalres) C.PrintToR(C.CString("listenAndServe: after eval.\n")) /* var s, t C.SEXP s = C.allocList(3) t = s C.Rf_protect(t) C.SetTypeToLANGSXP(&s) //C.SETCAR(t, R_fcall) C.SETCAR(t, handler_) t = C.CDR(t) C.SETCAR(t, rawmsg) evalres := C.eval(s, rho_) C.Rf_protect(evalres) */ C.PrintToR(C.CString("nnListenAndServe: done with eval.\n")) if C.TYPEOF(evalres) != C.RAWSXP { fmt.Printf("rats! handler result was not RAWSXP raw bytes!\n") } else { //fmt.Printf("recv: %s\n", message) err = c.WriteMessage(mt, message) if err != nil { fmt.Println("write error: ", err) } } C.Rf_unprotect(3) } // end handler func http.HandleFunc("/", webSockHandler) err := http.ListenAndServe(addr, nil) if err != nil { fmt.Println("ListenAndServe: ", err) } return C.R_NilValue }