1 /*
2  * The MIT License (MIT)
3  *
4  * Copyright (c) 2014 Richard Andrew Cattermole
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 module dakka.base.impl.remote;
25 import dakka.base.impl.defs;
26 import dakka.base.defs;
27 import std.traits : ParameterIdentifierTuple, ParameterTypeTuple, ReturnType, isArray, isSomeString;
28 
29 pure string generateFuncRemoteHandler(T : Actor, string m, T t = T.init)() {
30 	string ret;
31 
32 	ret ~= "            if(supervisor !is null && !getDirector().validAddressIdentifier(remoteAddressIdentifier)) {\n";
33 	ret ~= "                if (supervisor.isLocalInstance || getDirector().validAddressIdentifier((cast(ActorRef!(Actor))supervisor).remoteAddressIdentifier) && !supervisor.isDying_) {\n";
34 	ret ~= "                    (cast()supervisor).onChildError(this, \"Node instance is on a remote server. But it has been disconnected.\");\n";
35 	ret ~= "                } else {\n";
36 	ret ~= "                    die();\n";
37 	ret ~= "                }\n";
38 	ret ~= "            }\n";
39 
40 	ret ~= "            auto cereal = Cerealiser();\n";
41 
42 	alias ptt = ParameterTypeTuple!(mixin("t." ~ m));
43 	foreach(i, n; ParameterIdentifierTuple!(mixin("t." ~ m))) {
44 		static if (is(ptt[i] == class) && is(ptt[i] : Actor)) {
45 			ret ~= "            cereal.write(DakkaActorRefWrapper(" ~ n ~ ".identifier, " ~ n ~ ".isLocalInstance_ ? null : (" ~ n ~ ".remoteAddressIdentifier == remoteAddressIdentifier ? null : " ~ n ~ ".remoteAddressIdentifier)));\n";
46 		} else {
47 			ret ~= "            cereal.write(" ~ n ~ ");\n";
48 		}
49 	}
50 	
51 	static if (hasReturnValue!(T, m)) {
52 		// wait for output from central.d -> reconstruct args return
53 		ret ~= "            ubyte[] odata = getDirector().callClassBlocking(remoteAddressIdentifier, identifier, \"" ~ m ~ "\", cast(ubyte[])cereal.bytes);\n";
54 		ret ~= "            auto decereal = Decerealiser(odata);\n";
55 		// blocking request.
56 
57 		static if (is(ReturnType!(mixin("t." ~ m)) == class) && is(ReturnType!(mixin("t." ~ m)) : Actor)) {
58 			ret ~= "            return grabActorFromData!(" ~ typeText!(ReturnType!(__traits(getMember, t, m))) ~ ")(decereal);";
59 		} else {
60             if (isArray!(ReturnType!(__traits(getMember, t, m))) && !isSomeString!(ReturnType!(__traits(getMember, t, m)))) {
61                 ret ~= "            import dakka.base.remotes.messages;\n";
62                 ret ~= "            RawConvTypes!(string[]) ret;\n";
63                 ret ~= "            ret.bytes = odata;\n";
64                 ret ~= "            return ret.value;\n";
65             } else
66 			    ret ~= "            return decereal.value!(" ~ typeText!(ReturnType!(__traits(getMember, t, m))) ~ ");\n";
67 		}
68 	} else {
69 		// non blocking request
70 		ret ~= "            getDirector().callClassNonBlocking(remoteAddressIdentifier, identifier, \"" ~ m ~ "\", cast(ubyte[])cereal.bytes);\n";
71 	}
72 	return ret;
73 }