private void sendRpcReply(ErlPid from, ErlRef eref, IErlObject reply) { if (from.Empty) { return; } Node.Send(from, ErlTuple.Create(eref, reply)); }
private void threadSpinCore() { // For Erlang I/O protocol see: // http://erlang.org/doc/apps/stdlib/io_protocol.html var patterns = new ErlPatternMatcher { { "{'$gen_call', {~v::pid(), ~v::ref()}, {call, ~v::atom(), ~v::atom(), ~v::list(), ~v}}".ErlArgs(P, R, M, F, A, G), (_p, _t, b, a) => rpcCall( b.Cast <ErlPid>(P), b.Cast <ErlRef>(R), b.Cast <ErlAtom>(M), b.Cast <ErlAtom>(F), b.Cast <ErlList>(A), b[G]) }, { "{'$gen_cast', {cast, ~v::atom(), ~v::atom(), ~v::list(), ~v}}".ErlArgs(M, F, A, G), (_p, _t, b, a) => rpcCall( ErlPid.Null, ErlRef.Null, b.Cast <ErlAtom>(M), b.Cast <ErlAtom>(F), b.Cast <ErlList>(A), b[G]) }, { "{_, {~v::pid(), ~v::ref()}, _Cmd}".ErlArgs(P, R), (_p, _t, b, a) => ErlTuple.Create(b[P], b[R], ErlTuple.Create(ConstAtoms.Error, ConstAtoms.Unsupported)) }, }; while (m_Active) { Tuple <IErlObject, int> res = Self.ReceiveMatch(patterns, 1500); switch (res.Item2) { case -2: /* timeout */ break; case -1: /* no match */ App.Log.Write(Log.MessageType.Warning, StringConsts.ERL_INVALID_RPC_REQUEST_ERROR, res.Item1.ToString()); break; default: if (res.Item1 == null) { break; } var t = (ErlTuple)res.Item1; var pid = t.Cast <ErlPid>(0); var eref = t.Cast <ErlRef>(1); var reply = t[2]; sendRpcReply(pid, eref, reply); break; } } App.Log.Write( Log.MessageType.Info, StringConsts.ERL_STOPPING_SERVER.Args(Node.NodeName, "RPC")); m_Thread = null; }
private IErlObject rpcCall(ErlPid from, ErlRef eref, ErlAtom mod, ErlAtom fun, ErlList args, IErlObject groupLeader) { // We spawn a new task, so that RPC calls wouldn't block the RPC server thread Task.Factory.StartNew(() => { var type = Type.GetType(mod); if (type == null) { sendRpcReply(from, eref, ErlTuple.Create(ConstAtoms.Error, "unknown type: {0}".Args(mod))); return; } // TODO: add LRU caching //var method = type.GetMethod(fun.Value, BindingFlags.Static | BindingFlags.Public); string methodName = fun.Value; if (args.Count == 0) { var pi = type.GetProperty(fun, BindingFlags.Static | BindingFlags.Public); if (pi != null) { try { var result = pi.GetValue(null, null); sendRpcReply(from, eref, ErlTuple.Create(ConstAtoms.Ok, result.ToErlObject())); } catch (Exception e) { sendRpcReply(from, eref, ErlTuple.Create(ConstAtoms.Error, new ErlString(e.Message))); }; return; } } var mi = type.GetMethods(BindingFlags.Static | BindingFlags.Public) .Where(m => m.Name == methodName && m.GetParameters().Count() == args.Count) .FirstOrDefault(); if (mi == null) { sendRpcReply(from, eref, ErlTuple.Create(ConstAtoms.Error, "unknown method: {0}".Args(fun))); return; } var pars = mi.GetParameters(); var margs = new object[pars.Length]; for (int i = 0; i < pars.Length; i++) { var par = pars[i]; var val = args[i]; margs[i] = val.AsType(par.ParameterType); } try { var result = mi.Invoke(type, margs); sendRpcReply(from, eref, ErlTuple.Create(ConstAtoms.Ok, result.ToErlObject())); } catch (Exception e) { sendRpcReply(from, eref, ErlTuple.Create(ConstAtoms.Error, new ErlString(e.Message))); } }); return((IErlObject)null); }