func (rpcs *rpcRex) HandleCall(message *etf.Term, from *etf.Tuple) (reply *etf.Term) { nLog("REX: HandleCall: %#v, From: %#v", *message, *from) var replyTerm etf.Term valid := false switch req := (*message).(type) { case etf.Tuple: if len(req) > 0 { switch act := req[0].(type) { case etf.Atom: if string(act) == "call" { valid = true if fun, ok := rpcs.callMap[modFun{string(req[1].(etf.Atom)), string(req[2].(etf.Atom))}]; ok { replyTerm = fun(req[3].(etf.List)) } else { replyTerm = etf.Term(etf.Tuple{etf.Atom("badrpc"), etf.Tuple{etf.Atom("EXIT"), etf.Tuple{etf.Atom("undef"), etf.List{etf.Tuple{req[1], req[2], req[3], etf.List{}}}}}}) } } } } } if !valid { replyTerm = etf.Term(etf.Tuple{etf.Atom("badrpc"), etf.Atom("unknown")}) } reply = &replyTerm return }
// shutdown request // takes no arguments func (r *Relay) rpcShutdown(terms etf.List) etf.Term { if len(terms) != 0 { return etf.Term(etf.Tuple{etf.Atom("error"), etf.Atom("badarith")}) } r.shutdown() r.shutdownChan <- struct{}{} return etf.Term(etf.Atom("ok")) }
// rpc funcs for erlang nodes // args must be in form `[Name:string]` // returns either `ok` or `{error, Reason}` func (r *Relay) rpcCreateFS(terms etf.List) etf.Term { if len(terms) != 1 { return etf.Term(etf.Tuple{etf.Atom("error"), etf.Atom("badarith")}) } t := terms[0] if _, ok := t.(string); !ok { return etf.Term(etf.Tuple{etf.Atom("error"), etf.Atom("badarg")}) } name := t.(string) err := r.createFS(name) if err != nil { println("cannot create fs: ", err) return etf.Term(etf.Tuple{etf.Atom("error"), etf.Atom("failed-to-create-fs")}) } return etf.Term(etf.Atom("ok")) }
// HandleCall handles incoming messages from `gen_server:call/2`, if returns non-nil term, // then calling process have reply // Call `gen_server:call({go_srv, gonode@localhost}, Message)` at Erlang node func (gs *gonodeSrv) HandleCall(message *etf.Term, from *etf.Tuple) (reply *etf.Term) { log.Printf("GO_SRV: HandleCall: %#v, From: %#v", *message, *from) // Just create new term tuple where first element is atom 'ok', second 'go_reply' and third is original message replyTerm := etf.Term(etf.Tuple{etf.Atom("ok"), etf.Atom("go_reply"), *message}) reply = &replyTerm return }
// args must be in form `[FSName:string, DevName:string, isSensor/optional, // isAffector/optional] // return `{ok, Pid}` or `{error, Reason}` func (r *Relay) rpcCreateDevice(terms etf.List) etf.Term { if len(terms) != 3 { return etf.Term(etf.Tuple{etf.Atom("error"), etf.Atom("badarith")}) } tFSName := terms[0] if _, ok := tFSName.(string); !ok { return etf.Term(etf.Tuple{etf.Atom("error"), etf.Atom("badarg")}) } fsName := tFSName.(string) tDeviceName := terms[1] if _, ok := tDeviceName.(string); !ok { return etf.Term(etf.Tuple{etf.Atom("error"), etf.Atom("badarg")}) } deviceName := tDeviceName.(string) if _, ok := terms[2].(etf.List); !ok { return etf.Term(etf.Tuple{etf.Atom("error"), etf.Atom("badarg")}) } isSensor, isAffector, err := parseCreateFlags(terms[2].(etf.List)) if err != nil { return etf.Term(etf.Tuple{etf.Atom("error"), etf.Atom("badarg")}) } fullName, err := r.createDevice(fsName, deviceName, isSensor, isAffector) if err != nil { println("failed to create device: ", err) return etf.Term(etf.Tuple{etf.Atom("error"), etf.Atom("failed-to-create-device")}) } return etf.Term(etf.Tuple{etf.Atom("ok"), fullName}) }
// affecter data request // msg must be atom `req` func (d *deviceProc) HandleCall(msg *etf.Term, from *etf.Tuple) *etf.Term { println("handling call") if atom, ok := (*msg).(etf.Atom); !ok { t := etf.Term(etf.Tuple{etf.Atom("error"), etf.Atom("badarg")}) return &t } else { if string(atom) != "req" { t := etf.Term(etf.Tuple{etf.Atom("error"), etf.Atom("badarg")}) return &t } buf := d.device.Affect() if buf == nil { t := etf.Term(etf.Tuple{etf.Atom("ok"), etf.Atom("nil")}) return &t } else { t := etf.Term(etf.Tuple{etf.Atom("ok"), buf}) return &t } } }
func (rpcs *rpcRex) HandleCall(message *etf.Term, from *etf.Tuple) (reply *etf.Term) { nLog("REX: HandleCall: %#v, From: %#v", *message, *from) switch req := (*message).(type) { case etf.Tuple: if len(req) > 0 { switch act := req[0].(type) { case etf.Atom: if string(act) == "call" { nLog("RPC CALL: Module: %#v, Function: %#v, Args: %#v, GroupLeader: %#v", req[1], req[2], req[3], req[4]) replyTerm := etf.Term(etf.Tuple{req[1], req[2]}) reply = &replyTerm } } } } if reply == nil { replyTerm := etf.Term(etf.Tuple{etf.Atom("badrpc"), etf.Atom("unknown")}) reply = &replyTerm } return }
func main() { // Parse CLI flags flag.Parse() setup_logging() write_pid() log.Println("node started") // Initialize new node with given name and cookie enode := node.NewNode(NodeName, Cookie) // Allow node be available on EpmdPort port err = enode.Publish(EpmdPort) if err != nil { log.Fatalf("Cannot publish: %s", err) } // Create channel to receive message when main process should be stopped completeChan := make(chan bool) // Initialize new instance of srv structure which implements Process behaviour eSrv := new(srv) // Spawn process with one arguments enode.Spawn(eSrv, completeChan) // RPC if EnableRPC { // Create closure eClos := func(terms etf.List) (r etf.Term) { r = etf.Term(etf.Tuple{etf.Atom("gonode"), etf.Atom("reply"), len(terms)}) return } // Provide it to call via RPC with `rpc:call(gonode@localhost, go_rpc, call, [as, qwe])` err = enode.RpcProvide("go_rpc", "call", eClos) if err != nil { log.Printf("Cannot provide function to RPC: %s", err) } } // Wait to stop <-completeChan log.Println("node finished") return }
func (nk *netKernel) HandleCall(message *etf.Term, from *etf.Tuple) (reply *etf.Term) { nLog("NET_KERNEL: HandleCall: %#v, From: %#v", *message, *from) switch t := (*message).(type) { case etf.Tuple: if len(t) == 2 { switch tag := t[0].(type) { case etf.Atom: if string(tag) == "is_auth" { nLog("NET_KERNEL: is_auth: %#v", t[1]) replyTerm := etf.Term(etf.Atom("yes")) reply = &replyTerm } } } } return }
func runNode() (enode *node.Node) { enode = node.NewNode(nodeName, nodeCookie) err := enode.Publish(nodePort) if err != nil { log.Printf("Cannot publish: %s", err) enode = nil } eSrv := new(eclusSrv) enode.Spawn(eSrv) eClos := func(terms etf.List) (r etf.Term) { r = etf.Term(etf.Tuple{etf.Atom("enode"), len(terms)}) return } err = enode.RpcProvide("enode", "lambda", eClos) if err != nil { log.Printf("Cannot provide function to RPC: %s", err) } return }
func main() { // Initialize new node with given name and cookie enode := node.NewNode("gonode@localhost", "123") // Allow node be available on 5588 port err := enode.Publish(5588) if err != nil { log.Fatalf("Cannot publish: %s", err) } // Create channel to receive message when main process should be stopped completeChan := make(chan bool) // Initialize new instance of gonodeSrv structure which implements Process behaviour eSrv := new(gonodeSrv) // Spawn process with one arguments enode.Spawn(eSrv, completeChan) // RPC // Create closure eClos := func(terms etf.List) (r etf.Term) { r = etf.Term(etf.Tuple{etf.Atom("gonode"), etf.Atom("reply"), len(terms)}) return } // Provide it to call via RPC with `rpc:call(gonode@localhost, go_rpc, call, [as, qwe])` err = enode.RpcProvide("go_rpc", "call", eClos) if err != nil { log.Printf("Cannot provide function to RPC: %s", err) } // Wait to stop <-completeChan return }
func (currNd *NodeDesc) ReadMessage(c net.Conn) (ts []etf.Term, err error) { sendData := func(headerLen int, data []byte) (int, error) { reply := make([]byte, len(data)+headerLen) if headerLen == 2 { binary.BigEndian.PutUint16(reply[0:headerLen], uint16(len(data))) } else { binary.BigEndian.PutUint32(reply[0:headerLen], uint32(len(data))) } copy(reply[headerLen:], data) dLog("Write to enode: %v", reply) return c.Write(reply) } switch currNd.state { case HANDSHAKE: var length uint16 if err = binary.Read(c, binary.BigEndian, &length); err != nil { return } msg := make([]byte, length) if _, err = io.ReadFull(c, msg); err != nil { return } dLog("Read from enode %d: %v", length, msg) switch msg[0] { case 'n': sn := currNd.read_SEND_NAME(msg) // Statuses: ok, nok, ok_simultaneous, alive, not_allowed sok := currNd.compose_SEND_STATUS(sn, true) _, err = sendData(2, sok) if err != nil { return } rand.Seed(time.Now().UTC().UnixNano()) currNd.challenge = rand.Uint32() // Now send challenge challenge := currNd.compose_SEND_CHALLENGE(sn) sendData(2, challenge) if err != nil { return } case 'r': sn := currNd.remote ok := currNd.read_SEND_CHALLENGE_REPLY(sn, msg) if ok { challengeAck := currNd.compose_SEND_CHALLENGE_ACK(sn) sendData(2, challengeAck) if err != nil { return } dLog("Remote: %#v", sn) ts = []etf.Term{etf.Term(etf.Tuple{etf.Atom("$go_set_node"), etf.Atom(sn.Name)})} } else { err = errors.New("bad handshake") return } } case CONNECTED: var length uint32 if err = binary.Read(c, binary.BigEndian, &length); err != nil { return } if length == 0 { dLog("Keepalive") sendData(4, []byte{}) return } r := &io.LimitedReader{c, int64(length)} if currNd.flag.isSet(DIST_HDR_ATOM_CACHE) { var ctl, message etf.Term if err = currNd.readDist(r); err != nil { break } if ctl, err = currNd.readCtl(r); err != nil { break } dLog("READ CTL: %#v", ctl) if message, err = currNd.readMessage(r); err != nil { break } dLog("READ MESSAGE: %#v", message) ts = append(ts, ctl, message) } else { msg := make([]byte, 1) if _, err = io.ReadFull(r, msg); err != nil { return } dLog("Read from enode %d: %#v", length, msg) switch msg[0] { case 'p': ts = make([]etf.Term, 0) for { var res etf.Term if res, err = currNd.readTerm(r); err != nil { break } ts = append(ts, res) dLog("READ TERM: %#v", res) } if err == io.EOF { err = nil } default: _, err = ioutil.ReadAll(r) } } } return }
func (es *eclusSrv) HandleCall(message *etf.Term, from *etf.Tuple) (reply *etf.Term) { log.Printf("ECLUS_SRV: HandleCall: %#v, From: %#v", *message, *from) replyTerm := etf.Term(etf.Tuple{etf.Atom("ok"), etf.Atom("eclus_reply"), *message}) reply = &replyTerm return }
func (gns *globalNameServer) HandleCall(message *etf.Term, from *etf.Tuple) (reply *etf.Term) { nLog("GLOBAL_NAME_SERVER: HandleCall: %#v, From: %#v", *message, *from) replyTerm := etf.Term(etf.Atom("reply")) reply = &replyTerm return }