コード例 #1
0
ファイル: rmq.go プロジェクト: glycerine/rmq
//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
}
コード例 #2
0
ファイル: rmq.go プロジェクト: go-binder/rmq
//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
}
コード例 #3
0
ファイル: rmq.go プロジェクト: glycerine/rmq
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
}
コード例 #4
0
ファイル: rmq.go プロジェクト: glycerine/rmq
//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
}
コード例 #5
0
ファイル: rmq.go プロジェクト: glycerine/rmq
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
}
コード例 #6
0
ファイル: rmq.go プロジェクト: go-binder/rmq
//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)
}
コード例 #7
0
ファイル: rmq.go プロジェクト: go-binder/rmq
//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
}
コード例 #8
0
ファイル: readframe.go プロジェクト: glycerine/rmq
//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
}
コード例 #9
0
ファイル: rmq.go プロジェクト: go-binder/rmq
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
}
コード例 #10
0
ファイル: rmq.go プロジェクト: go-binder/rmq
//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
}