ret += map + ".Read(" + "\"" + param_id + "\", out ";
if (IsDelegateType(type)) {
ret += "CallbackBase del_" + gen_id + ");\n";
- ret +=
- new_type + " " + gen_id + " = new " + new_type +
- "(GetPort(Port.Type.Callback, instance), new WeakReference(b), del_" +
- gen_id + ");\n";
-
+ ret += ReplaceAll(CB_DLELGATGE_CREATE)
+ .Change("<TYPE>", new_type)
+ .Change("<GEN_ID>", gen_id);
} else {
if (make_new_type) {
ret += new_type + " " + gen_id + ");\n";
for (const auto& i : decl.GetParameters()) {
m += ConvertTypeToSerializer(i->GetID(), i->GetID(), "map");
}
- return AddIndent(TAB_SIZE * 6, m);
+ return AddIndent(TAB_SIZE * 5, m);
});
}
std::string GenUnitMapParamInit(const Interface& iface,
const BaseType& base_type,
const std::string& type_str);
- std::string GetStructureSerialize(const Structure& st);
- std::string GetStructureDeserialize(const Structure& st);
- std::string GetStructTypeString(const BaseType& base_type);
- std::string GetStructTypeString(const Structure& st);
+ std::string GetStructureSerialize(const Structure& st);
+ std::string GetStructureDeserialize(const Structure& st);
+ std::string GetStructTypeString(const BaseType& base_type);
+ std::string GetStructTypeString(const Structure& st);
private:
std::map<std::string, std::string> type_map_;
R"__cs_cb(
using System;
using System.Collections.Generic;
+using System.Collections.Concurrent;
+using System.Threading;
+using System.Reflection;
using Tizen.Applications;
using Tizen.Applications.RPCPort;
)__cs_cb";
-
const char CB_REMOTE_EXCEPTION_BASE[] =
R"__cs_cb(
public class RemoteException : Exception
R"__cs_cb( private Port _port;
private WeakReference _service;
private bool _valid = true;
-
+ internal LocalExecution _lem;
)__cs_cb";
const char CB_CALLBACK_INVOKE_METHOD[] =
R"__cs_cb(
public void Invoke($$)
{
- if (_port == null)
+ if (_port == null && _lem == null)
throw new NotConnectedSocketException();
if (!_service.IsAlive)
throw new InvalidProtocolException();
if (Once && !_valid)
throw new InvalidCallbackException();
+ if (_lem != null && _lem._online == false)
+ throw new NotConnectedSocketException();
- using (var p = new Parcel())
- {
- UnitMap map = new UnitMap();
+ var p = new Parcel();
+ UnitMap map = new UnitMap();
- map.Write("[METHOD]", (int)MethodId.__Callback);
- map.Write("delegate", this);
+ map.Write("[METHOD]", (int)MethodId.__Callback);
+ map.Write("delegate", this);
$$
- map.Serialize(p);
+ map.Serialize(p);
+
+ if (_lem != null)
+ {
+ _lem.SendRequest(p);
+ } else
+ {
// Send
p.Send(_port);
- _valid = false;
}
+ _valid = false;
}
)__cs_cb";
}
)__cs_cb";
+const char CB_DLELGATGE_CREATE[] =
+R"__cs_cb(
+Port cb_port;
+if (b._lem != null)
+ cb_port = null;
+else
+ cb_port = GetPort(Port.Type.Callback, instance);
+
+<TYPE> <GEN_ID> = new <TYPE>(cb_port, new WeakReference(b), del_<GEN_ID>);
+
+if (b._lem != null)
+ param3._lem = b._lem;
+)__cs_cb";
+
+
const char CB_WRITE_BUNDLE[] =
R"__cs_cb(
if (param.$$ != null)
GenBrace(stream, 0, [&]() {
stream << "namespace " << GetFileNamespace() << NLine(1);
GenBrace(stream, 0, [&]() {
+ GenLemBase(stream);
GenRemoteException(stream);
GenStructures(stream);
stream << Tab(1) << "namespace Proxy" << NLine(1);
});
}
+void CsProxyGen::GenLemBase(std::ofstream& stream) {
+ stream << CB_LEM_BASE;
+}
+
void CsProxyGen::GenInterfaces(std::ofstream& stream) {
for (auto& i : GetDocument().GetBlocks()) {
if (i->GetType() != Block::TYPE_INTERFACE) continue;
}
void CsProxyGen::GenCtor(std::ofstream& stream, const Interface& iface) {
- const char* m = "public $$(string appId) => _appId = appId;\n";
-
- stream << NLine(1);
- GenTemplate(AddIndent(TAB_SIZE * 3, m), stream,
- [&]() -> std::string { return iface.GetID(); });
+ ReplaceAll(CB_CONSTRUCTOR_METHOD)
+ .Change("<NAME>", iface.GetID())
+ .Out(stream);
}
void CsProxyGen::GenConnectMethod(std::ofstream& stream,
st += Tab(5) + "{" + NLine(1);
if (!l.empty()) st += AddIndent(TAB_SIZE * 6, l) + NLine(1);
- st += CB_INVOCATION_MID + NLine(1);
+
// Deserialize
if (decl.GetMethodType() == Declaration::MethodType::ASYNC) {
+ st += CB_INVOCATION_ASYNC_MID + NLine(1);
st += Tab(5) + "}";
return st;
+ } else {
+ st += CB_INVOCATION_SYNC_MID + NLine(1);
}
st += NLine(1) + AddIndent(TAB_SIZE * 5, CB_INVOCATION_RECEIVE);
void GenInvocation(std::ofstream& stream, const Declaration& decl);
void GenEventMethod(std::ofstream& stream, const Interface& iface);
void GenMemberData(std::ofstream& stream, const Interface& iface);
+ void GenLemBase(std::ofstream& stream);
};
} // namespace version2
private bool _online = false;
private string _appId;
private Object _lock = new Object();
+ private bool _connecting = false;
+ private LocalExecution _lem;
+ private SynchronizationContext _async_context = TizenSynchronizationContext.Current;
<CALLBACK_LIST>
)__cs_cb";
+
+const char CB_LEM_BASE[] =
+R"__cs_cb( internal class LocalExecution
+ {
+ internal bool IsListen = false;
+ object _instance = null;
+ string _instance_id = null;
+ string _appId = null;
+ static int _seq = 0;
+ MethodInfo _send = null;
+ MethodInfo _connect = null;
+ MethodInfo _disconnect = null;
+ ConcurrentQueue<Parcel> _result = new ConcurrentQueue<Parcel>();
+
+ internal LocalExecution(string appId, string interfaceName)
+ {
+ string current_appid = Application.Current.ApplicationInfo.ApplicationId;
+
+ if (current_appid != appId)
+ return;
+
+ _seq++;
+ _instance_id = appId + "::" + _seq.ToString();
+ _appId = appId;
+
+ Assembly assembly = Assembly.GetExecutingAssembly();
+ Type type = null;
+
+ foreach (Type t in assembly.GetTypes())
+ {
+ if (t.Name != interfaceName)
+ continue;
+
+ string[] name = t.FullName?.Split('.');
+
+ if (name == null || name.Length != 4)
+ continue;
+
+ if (name[0] == "RPCPort" && name[2] == "Stub")
+ {
+ if (type == null)
+ {
+ type = t;
+ }
+ else
+ {
+ type = null;
+ break;
+ }
+ }
+ }
+
+ if (type == null)
+ return;
+
+ MethodInfo getInstance = type.GetMethod("GetInstance", BindingFlags.Static | BindingFlags.NonPublic);
+ if (getInstance == null) { return; }
+
+ _instance = getInstance.Invoke(null, null);
+ if (_instance == null) { return; }
+
+ _send = type.GetMethod("OnLemReceivedEvent", BindingFlags.NonPublic | BindingFlags.Instance);
+ if (_send == null) { return; }
+
+ _connect = type.GetMethod("OnLemConnectedEvent", BindingFlags.NonPublic | BindingFlags.Instance);
+ if (_connect == null) { return; }
+
+ _disconnect = type.GetMethod("OnLemDisconnectedEvent", BindingFlags.NonPublic | BindingFlags.Instance);
+ if (_disconnect == null) { return; }
+
+ MethodInfo getListen = type.GetMethod("GetListenStatus", BindingFlags.NonPublic | BindingFlags.Instance);
+ if (getListen == null) { return; }
+
+ object ret = getListen.Invoke(_instance, null);
+ if (ret == null) { return; }
+ IsListen = (bool)ret;
+ }
+
+ internal void Connect(object proxy_instance)
+ {
+ _connect.Invoke(_instance, new object[] { proxy_instance, _appId, _instance_id });
+ }
+
+ internal void Disconnect()
+ {
+ _disconnect.Invoke(_instance, new object[] { _appId, _instance_id });
+ }
+
+ internal void Send(Parcel p)
+ {
+ _send.Invoke(_instance, new object[] { _instance_id, p});
+ }
+
+ internal void Send(Parcel p, ref Parcel resutl)
+ {
+ Send(p);
+
+ int count = 0;
+ while (_result.IsEmpty && count++ < 100)
+ Thread.Sleep(100);
+
+ if (ResultQueuePop(out resutl))
+ {
+ Tizen.Log.Error("RPC_PORT", "ResultQueuePop");
+ return;
+ }
+
+ Tizen.Log.Error("RPC_PORT_PROXY", "Failed to get result from server");
+ throw new InvalidIOException();
+ }
+
+ internal void ResultQueuePush(Parcel p)
+ {
+ _result.Enqueue(p);
+ }
+
+ internal bool ResultQueuePop(out Parcel p)
+ {
+ return _result.TryDequeue(out p);
+ }
+ }
+)__cs_cb";
+
const char CB_DATA_CALLBACK_LIST[] =
R"__cs_cb(
private List<CallbackBase> _delegateList = new List<CallbackBase>();
)__cs_cb";
const char CB_EVENT_PROCESS_EVENT_BASE[] =
R"__cs_cb(
- private void ProcessReceivedEvent(UnitMap map)
+ private void ProcessReceivedEvent(Parcel parcelReceived)
{
+ UnitMap map = new UnitMap();
+ map.Deserialize(parcelReceived);
+
+ int cmd;
+ map.Read("[METHOD]", out cmd);
+
+ if (cmd != (int)MethodId.__Callback)
+ {
+ return;
+ }
+
CallbackBase cb;
map.Read("delegate", out cb);
}
}
}
+
+ internal void OnLemReceivedEvent(Parcel parcelReceived)
+ {
+ _async_context.Post((data) =>
+ {
+ ProcessReceivedEvent(parcelReceived);
+
+ }, null);
+ }
+
)__cs_cb";
const char CB_EVENT_RECEIVE_EVENT_BASE[] =
using (parcelReceived)
{
- UnitMap map = new UnitMap();
- map.Deserialize(parcelReceived);
-
- int cmd;
- map.Read("[METHOD]", out cmd);
-
- if (cmd != (int)MethodId.__Callback)
- {
- return;
- }
-
- ProcessReceivedEvent(map);
+ ProcessReceivedEvent(parcelReceived);
}
)__cs_cb";
protected override void OnConnectedEvent(string endPoint, string portName, Port port)
{
_online = true;
+ _connecting = false;
Connected?.Invoke(this, null);
}
Disconnected?.Invoke(this, null);
}
+ internal void OnLemDisconnectedEvent()
+ {
+ _async_context.Post((data) =>
+ {
+ OnDisconnectedEvent(null, null);
+
+ }, null);
+
+ }
+
+ internal void OnLemResultEvent(Parcel result)
+ {
+ _lem.ResultQueuePush(result);
+ }
+
protected override void OnRejectedEvent(string endPoint, string portName)
{
+ _connecting = false;
Rejected?.Invoke(this, null);
}
<PROCESS_EVENT_BASE>
}
)__cs_cb";
+const char CB_CONSTRUCTOR_METHOD[] =
+R"__cs_cb(
+ public <NAME>(string appId)
+ {
+ _appId = appId;
+ _lem = new LocalExecution(appId, "<NAME>");
+ }
+)__cs_cb";
+
const char CB_CONNECT_METHOD[] =
R"__cs_cb(
/// <summary>
/// <remark> If you want to use this method, you must add privileges.</remark>
public void Connect()
{
- Connect(_appId, "$$");
+ if (_lem.IsListen)
+ {
+ if (_online || _connecting)
+ throw new InvalidIDException();
+
+ _connecting = true;
+ _lem.Connect(this);
+
+ _async_context.Post((data) =>
+ {
+ OnConnectedEvent(null, null, null);
+ }, null);
+ }
+ else
+ {
+ Connect(_appId, "$$");
+ }
}
/// <summary>
/// </exception>
public void Disconnect()
{
- Port?.Disconnect();
+ if (_lem.IsListen)
+ {
+ if (_online)
+ _lem.Disconnect();
+ }
+ else
+ {
+ Port?.Disconnect();
+ }
+ _online = false;
}
/// <summary>
/// <remark> If you want to use this method, you must add privileges.</remark>
public void ConnectSync()
{
- ConnectSync(_appId, "$$");
+ if (_lem.IsListen)
+ {
+ if (_online || _connecting)
+ throw new InvalidIDException();
+
+ _connecting = true;
+ _lem.Connect(this);
+ OnConnectedEvent(null, null, null);
+ }
+ else
+ {
+ ConnectSync(_appId, "$$");
+ }
}
)__cs_cb";
}
)__cs_cb";
-const char CB_INVOCATION_MID[] =
+const char CB_INVOCATION_ASYNC_MID[] =
R"__cs_cb( // Send
- p.Send(Port);
+ if (_lem.IsListen)
+ {
+ _lem.Send(p);
+ }
+ else
+ {
+ p.Send(Port);
+ }
+)__cs_cb";
+
+const char CB_INVOCATION_SYNC_MID[] =
+R"__cs_cb( // Send
+ Parcel ret_parcel = new Parcel();
+ // Send
+ if (_lem.IsListen)
+ {
+ _lem.Send(p, ref ret_parcel);
+ }
+ else
+ {
+ p.Send(Port);
+ }
)__cs_cb";
const char CB_INVOCATION_RECEIVE[] =
R"__cs_cb( UnitMap mapReceived;
-
- // Receive
- ConsumeCommand(out mapReceived, Port, header);
-
+ if (_lem.IsListen)
+ {
+ mapReceived = new UnitMap();
+ mapReceived.Deserialize(ret_parcel);
+ }
+ else
+ {
+ // Receive
+ ConsumeCommand(out mapReceived, Port, header);
+ }
if (mapReceived == null)
{
GenBrace(stream, 0, [&]() {
stream << "namespace " << GetFileNamespace() << NLine(1);
GenBrace(stream, 0, [&]() {
+ GenLemBase(stream);
GenRemoteException(stream);
GenStructures(stream);
stream << Tab(1) << "namespace Stub" << NLine(1);
});
}
+void CsStubGen::GenLemBase(std::ofstream& stream) {
+ stream << CB_LEM_BASE;
+}
+
void CsStubGen::GenInterfaces(std::ofstream& stream) {
for (auto& i : GetDocument().GetBlocks()) {
if (i->GetType() != Block::TYPE_INTERFACE) continue;
stream << CB_ON_RECEIVED_EVENT_FRONT;
for (const auto& i : iface.GetDeclarations()) {
if (i->GetMethodType() == Declaration::MethodType::DELEGATE) continue;
- stream << Tab(7) << "case MethodId." << i->GetID() << ":" << NLine(1);
- GenBrace(stream, TAB_SIZE * 8, [&]() {
+ stream << Tab(6) << "case MethodId." << i->GetID() << ":" << NLine(1);
+ GenBrace(stream, TAB_SIZE * 7, [&]() {
GenInvocation(stream, *i);
- stream << Tab(9) << "break;" << NLine(1);
+ stream << Tab(8) << "break;" << NLine(1);
});
}
stream << CB_ON_RECEIVED_EVENT_BACK;
std::string v = "param" + std::to_string(cnt);
std::string c = ConvertTypeToDeserializer(
i->GetParameterType().GetBaseType(), v, i->GetID(), "map");
- stream << AddIndent(TAB_SIZE * 9, c);
+ stream << AddIndent(TAB_SIZE * 8, c);
cnt++;
}
.Change("<INVOCATION>",
AddIndent(TAB_SIZE, GetInvocationMethod(decl)));
- stream << AddIndent(TAB_SIZE * 9, m);
+ stream << AddIndent(TAB_SIZE * 8, m);
// Serialize
if (decl.GetMethodType() == Declaration::MethodType::ASYNC)
return;
cnt = 0;
- m = CB_INVOCATION_RESULT_PRE;
- m += "result_map.Serialize(result);\n";
- m += "result.Send(port);\n";
- stream << AddIndent(TAB_SIZE * 9, m);
+ m = CB_INVOCATION_RESULT;
+ stream << AddIndent(TAB_SIZE * 8, m);
}
void CsStubGen::GenConnectedEvent(std::ofstream& stream) {
std::string GetInvocationMethodParam(const Declaration& decl, bool hasRet);
std::string GetInvocationMethod(const Declaration& decl);
std::string GetWriteOutParam(const Declaration& decl);
+ void GenLemBase(std::ofstream& stream);
};
} // namespace version2
private Type _serviceType;
private static readonly string _tidlVersion = "<VERSION>";
private Dictionary<MethodId, List<string>> _privilege_map = new Dictionary<MethodId, List<string>>();
+ private static Message _instance;
+ private bool _isListen = false;
+ private SynchronizationContext _async_context = TizenSynchronizationContext.Current;
+)__cs_cb";
+
+const char CB_LEM_BASE[] =
+R"__cs_cb( internal class LocalExecution
+ {
+ object _instance = null;
+ MethodInfo _send_result = null;
+ MethodInfo _send_request = null;
+ MethodInfo _disconnect = null;
+
+ internal bool _online = false;
+
+ internal LocalExecution (object instance)
+ {
+ Type type = instance.GetType();
+
+ if (type == null)
+ return;
+
+ _send_result = type.GetMethod("OnLemResultEvent", BindingFlags.NonPublic | BindingFlags.Instance);
+ if (_send_result == null) { return; }
+
+ _send_request = type.GetMethod("OnLemReceivedEvent", BindingFlags.NonPublic | BindingFlags.Instance);
+
+ _disconnect = type.GetMethod("OnLemDisconnectedEvent", BindingFlags.NonPublic | BindingFlags.Instance);
+ if (_disconnect == null) { return; }
+
+ _instance = instance;
+ _online = true;
+
+ }
+
+ internal void SendResult(Parcel result)
+ {
+ _send_result.Invoke(_instance, new object[] {result});
+ }
+
+ internal void SendRequest(Parcel result)
+ {
+ if (_send_request != null)
+ _send_request.Invoke(_instance, new object[] { result });
+ }
+
+ internal void Disconnect()
+ {
+ if (_online)
+ _disconnect.Invoke(_instance, null);
+ _online = false;
+ }
+ }
)__cs_cb";
const char CB_SERVICE_BASE_FRONT[] =
{
internal bool _is_app = true;
internal List<string> _privileges;
+ internal LocalExecution _lem;
/// <summary>
/// The client app ID
/// </exception>
public void Disconnect()
{
- Port?.Disconnect();
- Port = null;
+ if(_lem != null)
+ {
+ _lem.Disconnect();
+ }
+ else
+ {
+ Port?.Disconnect();
+ Port = null;
+ }
}
/// <summary>
return false;
}
+ return OnReceivedEvent(instance, port, p);
+ }
+
+ internal void OnLemReceivedEvent(string instance, Parcel p)
+ {
+ if (Thread.CurrentThread.ManagedThreadId != 1)
+ {
+ _async_context.Post((data) =>
+ {
+ ((Message)data).OnReceivedEvent(instance, null, p);
+ }, this);
+ }
+ else
+ {
+ OnReceivedEvent(instance, null, p);
+ }
+ }
+
+ internal bool OnReceivedEvent(string instance, Port port, Parcel p)
+ {
try
{
ServiceBase b = null;
return false;
}
- using (var result = new Parcel())
- {
- int cmd;
- UnitMap map = new UnitMap();
- map.Deserialize(p);
+ var result = new Parcel();
- map.Read("[METHOD]", out cmd);
+ int cmd;
+ UnitMap map = new UnitMap();
+ map.Deserialize(p);
- switch ((MethodId)cmd)
- {
+ map.Read("[METHOD]", out cmd);
+
+ switch ((MethodId)cmd)
+ {
)__cs_cb";
const char CB_ON_RECEIVED_EVENT_BACK[] =
R"__cs_cb(
- default:
- return false;
- }
+ default:
+ return false;
}
return true;
s.LoadPrivilege();
s.Instance = instance;
s.Port = GetPort(Port.Type.Callback, instance);
+ _services.Add(s);
s.OnCreate();
+ }
+
+ internal void OnLemConnectedEvent(object proxy_instance, string sender, string instance)
+ {
+ ServiceBase s = Activator.CreateInstance(_serviceType) as ServiceBase;
+ s.Sender = sender;
+ s.LoadPrivilege();
+ s.Instance = instance;
+ s._lem = new LocalExecution(proxy_instance);
_services.Add(s);
+ if (Thread.CurrentThread.ManagedThreadId != 1)
+ {
+ _async_context.Post((data) =>
+ {
+ ((ServiceBase)data).OnCreate();
+ }, s);
+ }
+ else
+ {
+ s.OnCreate();
+ }
}
)__cs_cb";
{
if (i.Instance.Equals(instance))
{
+ if (i._lem != null)
+ i._lem._online = false;
+
i.OnTerminate();
_services.Remove(i);
break;
}
}
}
+
+ internal void OnLemDisconnectedEvent(string sender, string instance)
+ {
+ if (Thread.CurrentThread.ManagedThreadId != 1)
+ {
+ _async_context.Post((data) =>
+ {
+ ((Message)data).OnDisconnectedEvent(sender, instance);
+ }, this);
+ }
+ else
+ {
+ OnDisconnectedEvent(sender, instance);
+ }
+ }
)__cs_cb";
const char CB_CTOR_FRONT[] =
R"__cs_cb(
+ internal static Message GetInstance()
+ {
+ return _instance;
+ }
+
+ internal bool GetListenStatus()
+ {
+ return _isListen;
+ }
+
public $$() : base("$$")
{
+ _instance = this;
)__cs_cb";
const char CB_COMMON_METHODS[] =
throw new ArgumentException("Invalid type");
_serviceType = serviceType;
Listen();
+ _isListen = true;
}
/// <summary>
{
foreach (var i in _services)
{
+ if (i._lem != null)
+ i._lem._online = false;
i.OnTerminate();
}
}
result_map.Write("[REMOTE_EXCEPTION]", ex);
})__cs_cb";
-constexpr const char CB_INVOCATION_RESULT_PRE[] =
+constexpr const char CB_INVOCATION_RESULT[] =
R"__cs_cb(
ParcelHeader header = p.GetHeader();
ParcelHeader resultHeader = result.GetHeader();
resultHeader.SetTag(_tidlVersion);
resultHeader.SetSequenceNumber(header.GetSequenceNumber());
-
result_map.Write("[METHOD]", (int)MethodId.__Result);
+result_map.Serialize(result);
+
+if (b._lem != null)
+ b._lem.SendResult(result);
+else
+ result.Send(port);
+
)__cs_cb";
#endif // IDLC_CS_GEN_VERSION2_CS_STUB_GENRATOR_CB_H_
\ No newline at end of file