示例#1
0
        private static ServicePlan Compile(Dictionary <MethodInfo, MethodCallExpression> expressions, object serviceObject)
        {
            // step: collect all types, methods, variables referenced in this expression
            var workerQueue = new Queue <KeyValuePair <MethodInfo, MethodCallExpression> >();

            foreach (var exp in expressions)
            {
                workerQueue.Enqueue(new KeyValuePair <MethodInfo, MethodCallExpression>(exp.Key, exp.Value));
            }

            var contexts = new Dictionary <MethodInfo, QueryContext>();

            while (workerQueue.Count > 0)
            {
                var exp     = workerQueue.Dequeue();
                var context = new QueryContext(serviceObject, exp.Value, exp.Key.Name);
                context.Collect();
                contexts.Add(exp.Key, context);
                foreach (var s in context.ExternalComposedSerivce.Where(s => !contexts.ContainsKey(s.Key)))
                {
                    workerQueue.Enqueue(new KeyValuePair <MethodInfo, MethodCallExpression>(s.Key, s.Value));
                }
            }

            // step: prepare service plan
            var codeGenerator = new CodeGenerator();
            var name          = serviceObject.GetType().Name + "." + codeGenerator.AppId;
            var plan          = new ServicePlan
            {
                DependentServices = contexts
                                    .SelectMany(c => c.Value.Services.Select(r => r.Value))
                                    .DistinctBy(s => s.Url)
                                    .ToArray(),
                Package = new ServicePackage()
            };

            SystemHelper.CreateOrCleanDirectory(name);

            // step: generate composed service code
            var sources = new HashSet <string>();
            var libs    = new HashSet <string>();
            var dir     = name + ".Source";

            SystemHelper.CreateOrCleanDirectory(dir);

            libs.Add(Path.Combine(Environment.GetEnvironmentVariable("DSN_ROOT"), "lib", "dsn.dev.csharp.dll"));
            libs.Add(Path.Combine(Environment.GetEnvironmentVariable("DSN_ROOT"), "lib", "Thrift.dll"));

            var code = codeGenerator.BuildRdsn(serviceObject.GetType(), contexts.Select(c => c.Value).ToArray());

            SystemHelper.StringToFile(code, Path.Combine(dir, name + ".cs"));
            sources.Add(Path.Combine(dir, name + ".cs"));

            libs.UnionWith(QueryContext.KnownLibs);

            // step: generate client code for all dependent services
            foreach (var s in contexts
                     .SelectMany(c => c.Value.Services.Select(r => r.Value))
                     .DistinctBy(s => s.PackageName)
                     .Select(s => s.ExtractSpec()))
            {
                var provider = SpecProviderManager.Instance().GetProvider(s.SType);
                Trace.Assert(null != provider, "Language provider missing for type " + s.SType);

                LinkageInfo linkInfo;
                var         err = provider.GenerateServiceClient(s, dir, ClientLanguage.Client_CSharp, ClientPlatform.Windows, out linkInfo);
                Trace.Assert(FlowErrorCode.Success == err);

                sources.UnionWith(linkInfo.Sources);
                libs.UnionWith(linkInfo.DynamicLibraries);
            }

            // step: fill service plan
            plan.Package.Spec = new ServiceSpec
            {
                SType               = ServiceSpecType.Thrift,
                MainSpecFile        = serviceObject.GetType().Name + ".thrift",
                ReferencedSpecFiles = plan.DependentServices
                                      .DistinctBy(s => s.PackageName)
                                      .Where(s => s.Spec.SType == ServiceSpecType.Thrift)
                                      .SelectMany(s =>
                {
                    var spec      = s.ExtractSpec();
                    var specFiles = new List <string> {
                        spec.MainSpecFile
                    };

                    SystemHelper.SafeCopy(Path.Combine(spec.Directory, spec.MainSpecFile),
                                          Path.Combine(name, spec.MainSpecFile), false);

                    foreach (var ds in spec.ReferencedSpecFiles)
                    {
                        specFiles.Add(ds);
                        SystemHelper.SafeCopy(Path.Combine(spec.Directory, ds), Path.Combine(name, ds), false);
                    }
                    return(specFiles);
                }
                                                  )
                                      .Distinct()
                                      .ToList(),
                Directory = name
            };
            plan.Package.MainSpec = ServiceContract.GenerateStandAloneThriftSpec(serviceObject.GetType(), plan.Package.Spec.ReferencedSpecFiles);
            SystemHelper.StringToFile(plan.Package.MainSpec, Path.Combine(name, plan.Package.Spec.MainSpecFile));

            if (SystemHelper.RunProcess("php.exe", Path.Combine(Environment.GetEnvironmentVariable("DSN_ROOT"), "bin", "dsn.generate_code.php") + " " + Path.Combine(name, plan.Package.Spec.MainSpecFile) + " csharp " + dir + " json layer3") == 0)
            {
                sources.Add(Path.Combine(dir, serviceObject.GetType().Name + ".client.cs"));
                sources.Add(Path.Combine(dir, serviceObject.GetType().Name + ".server.cs"));
                sources.Add(Path.Combine(dir, "ThriftJsonHelper.cs"));
                sources.Add(Path.Combine(dir, serviceObject.GetType().Name + ".main.composed.cs"));
                sources.Add(Path.Combine(dir, serviceObject.GetType().Name + ".code.definition.cs"));
            }
            else
            {
                Console.Write("php codegen failed");
            }

            //grab thrift-generated files
            sources.UnionWith(Directory.GetFiles(Path.Combine(dir, "thrift"), "*.cs", SearchOption.AllDirectories));

            // step: generate composed service package
            CSharpCompiler.ToDiskAssembly(sources.ToArray(), libs.ToArray(), new string[] { },
                                          Path.Combine(name, name + ".exe"),
                                          true,
                                          true
                                          );

            libs.Add(Path.Combine(Environment.GetEnvironmentVariable("DSN_ROOT"), "lib", "dsn.core.dll"));
            libs.Add(Path.Combine(Environment.GetEnvironmentVariable("DSN_ROOT"), "lib", "zookeeper_mt.dll"));
            foreach (var lib in libs.Where(lib => !lib.StartsWith("System.")))
            {
                SystemHelper.SafeCopy(lib, Path.Combine(name, Path.GetFileName(lib)), false);
            }

            //Console.ReadKey();
            return(plan);
        }