Skip to content

Commit aa7efba

Browse files
Merge branch 'dev/hosthooks'
2 parents 597df77 + d0c52a1 commit aa7efba

38 files changed

+993
-3399
lines changed

ElectronNET.API/Electron.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,13 @@ public static class Electron
6060
/// </summary>
6161
public static Clipboard Clipboard { get { return Clipboard.Instance; } }
6262

63-
63+
/// <summary>
64+
/// Allows you to execute native JavaScript/TypeScript code from the host process.
65+
///
66+
/// It is only possible if the Electron.NET CLI has previously added an
67+
/// ElectronHostHook directory:
68+
/// <c>electronize add HostHook</c>
69+
/// </summary>
6470
public static HostHook HostHook { get { return HostHook.Instance; } }
6571
}
6672
}

ElectronNET.API/HostHook.cs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,18 @@
66

77
namespace ElectronNET.API
88
{
9+
/// <summary>
10+
/// Allows you to execute native JavaScript/TypeScript code from the host process.
11+
///
12+
/// It is only possible if the Electron.NET CLI has previously added an
13+
/// ElectronHostHook directory:
14+
/// <c>electronize add HostHook</c>
15+
/// </summary>
916
public sealed class HostHook
1017
{
1118
private static HostHook _electronHostHook;
1219
private static object _syncRoot = new object();
20+
string oneCallguid = Guid.NewGuid().ToString();
1321

1422
internal HostHook() { }
1523

@@ -32,18 +40,43 @@ internal static HostHook Instance
3240
}
3341
}
3442

43+
/// <summary>
44+
/// Execute native JavaScript/TypeScript code.
45+
/// </summary>
46+
/// <param name="socketEventName">Socket name registered on the host.</param>
47+
/// <param name="arguments">Optional parameters.</param>
3548
public void Call(string socketEventName, params dynamic[] arguments)
3649
{
37-
BridgeConnector.Socket.Emit(socketEventName, arguments);
50+
BridgeConnector.Socket.On(socketEventName + "Error" + oneCallguid, (result) =>
51+
{
52+
BridgeConnector.Socket.Off(socketEventName + "Error" + oneCallguid);
53+
Electron.Dialog.ShowErrorBox("Host Hook Exception", result.ToString());
54+
});
55+
56+
BridgeConnector.Socket.Emit(socketEventName, arguments, oneCallguid);
3857
}
3958

59+
/// <summary>
60+
/// Execute native JavaScript/TypeScript code.
61+
/// </summary>
62+
/// <typeparam name="T">Results from the executed host code.</typeparam>
63+
/// <param name="socketEventName">Socket name registered on the host.</param>
64+
/// <param name="arguments">Optional parameters.</param>
65+
/// <returns></returns>
4066
public Task<T> CallAsync<T>(string socketEventName, params dynamic[] arguments)
4167
{
4268
var taskCompletionSource = new TaskCompletionSource<T>();
4369
string guid = Guid.NewGuid().ToString();
4470

71+
BridgeConnector.Socket.On(socketEventName + "Error" + guid, (result) =>
72+
{
73+
BridgeConnector.Socket.Off(socketEventName + "Error" + guid);
74+
Electron.Dialog.ShowErrorBox("Host Hook Exception", result.ToString());
75+
});
76+
4577
BridgeConnector.Socket.On(socketEventName + "Complete" + guid, (result) =>
4678
{
79+
BridgeConnector.Socket.Off(socketEventName + "Error" + guid);
4780
BridgeConnector.Socket.Off(socketEventName + "Complete" + guid);
4881
T data;
4982

ElectronNET.CLI/Commands/Actions/DeployEmbeddedElectronFiles.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.IO;
4-
using System.Text;
1+
using System.IO;
52

63
namespace ElectronNET.CLI.Commands.Actions
74
{
@@ -11,7 +8,6 @@ public static void Do(string tempPath)
118
{
129
EmbeddedFileHelper.DeployEmbeddedFile(tempPath, "main.js");
1310
EmbeddedFileHelper.DeployEmbeddedFile(tempPath, "package.json");
14-
EmbeddedFileHelper.DeployEmbeddedFile(tempPath, "package-lock.json");
1511

1612
string hostApiFolder = Path.Combine(tempPath, "api");
1713
if (Directory.Exists(hostApiFolder) == false)
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
using System.Collections.Generic;
2+
using System.IO;
3+
4+
namespace ElectronNET.CLI.Commands.Actions
5+
{
6+
public static class DirectoryCopy
7+
{
8+
public static void Do(string sourceDirName, string destDirName, bool copySubDirs, List<string> ignoredSubDirs)
9+
{
10+
// Get the subdirectories for the specified directory.
11+
DirectoryInfo dir = new DirectoryInfo(sourceDirName);
12+
13+
if (!dir.Exists)
14+
{
15+
throw new DirectoryNotFoundException(
16+
"Source directory does not exist or could not be found: "
17+
+ sourceDirName);
18+
}
19+
20+
DirectoryInfo[] dirs = dir.GetDirectories();
21+
// If the destination directory doesn't exist, create it.
22+
if (!Directory.Exists(destDirName))
23+
{
24+
Directory.CreateDirectory(destDirName);
25+
}
26+
else
27+
{
28+
DirectoryInfo targetDir = new DirectoryInfo(destDirName);
29+
30+
foreach (FileInfo fileDel in targetDir.EnumerateFiles())
31+
{
32+
fileDel.Delete();
33+
}
34+
foreach (DirectoryInfo dirDel in targetDir.EnumerateDirectories())
35+
{
36+
dirDel.Delete(true);
37+
}
38+
}
39+
40+
41+
42+
43+
// Get the files in the directory and copy them to the new location.
44+
FileInfo[] files = dir.GetFiles();
45+
foreach (FileInfo file in files)
46+
{
47+
string temppath = Path.Combine(destDirName, file.Name);
48+
file.CopyTo(temppath, false);
49+
}
50+
51+
// If copying subdirectories, copy them and their contents to new location.
52+
if (copySubDirs)
53+
{
54+
foreach (DirectoryInfo subdir in dirs)
55+
{
56+
if (ignoredSubDirs.Contains(subdir.Name))
57+
{
58+
continue;
59+
}
60+
61+
string temppath = Path.Combine(destDirName, subdir.Name);
62+
Do(subdir.FullName, temppath, copySubDirs, ignoredSubDirs);
63+
}
64+
}
65+
}
66+
}
67+
}
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Runtime.InteropServices;
6+
using System.Text;
7+
using System.Threading.Tasks;
8+
using System.Xml;
9+
using System.Xml.Linq;
10+
11+
namespace ElectronNET.CLI.Commands
12+
{
13+
public class AddCommand : ICommand
14+
{
15+
public const string COMMAND_NAME = "add";
16+
public const string COMMAND_DESCRIPTION = "The add command needs to be invoked via 'add hosthook'. This creates a special folder for your custom npm package installation.";
17+
public const string COMMAND_ARGUMENTS = "hosthook";
18+
public static IList<CommandOption> CommandOptions { get; set; } = new List<CommandOption>();
19+
20+
21+
private string[] _args;
22+
23+
public AddCommand(string[] args)
24+
{
25+
_args = args;
26+
}
27+
28+
private static string ElectronHostHookFolderName = "ElectronHostHook";
29+
30+
public Task<bool> ExecuteAsync()
31+
{
32+
return Task.Run(() =>
33+
{
34+
if(_args.Length == 0)
35+
{
36+
Console.WriteLine("Specify 'hosthook' to add custom npm packages.");
37+
return false;
38+
}
39+
40+
if(_args[0].ToLowerInvariant() != "hosthook")
41+
{
42+
Console.WriteLine("Specify 'hosthook' to add custom npm packages.");
43+
return false;
44+
}
45+
46+
string aspCoreProjectPath = "";
47+
48+
// Maybe ToDo: Adding the possiblity to specify a path (like we did in the InitCommand, but this would require a better command args parser)
49+
aspCoreProjectPath = Directory.GetCurrentDirectory();
50+
51+
var currentDirectory = aspCoreProjectPath;
52+
53+
var targetFilePath = Path.Combine(currentDirectory, ElectronHostHookFolderName);
54+
55+
if(Directory.Exists(targetFilePath))
56+
{
57+
Console.WriteLine("ElectronHostHook directory already in place. If you want to start over, delete the folder and invoke this command again.");
58+
return false;
59+
}
60+
61+
Console.WriteLine("Adding the ElectronHostHook folder to your project...");
62+
63+
Directory.CreateDirectory(targetFilePath);
64+
65+
// Deploy related files
66+
EmbeddedFileHelper.DeployEmbeddedFile(targetFilePath, "index.ts", "ElectronHostHook.");
67+
EmbeddedFileHelper.DeployEmbeddedFile(targetFilePath, "connector.ts", "ElectronHostHook.");
68+
EmbeddedFileHelper.DeployEmbeddedFile(targetFilePath, "package.json", "ElectronHostHook.");
69+
EmbeddedFileHelper.DeployEmbeddedFile(targetFilePath, "tsconfig.json", "ElectronHostHook.");
70+
EmbeddedFileHelper.DeployEmbeddedFile(targetFilePath, ".gitignore", "ElectronHostHook.");
71+
72+
// npm for typescript compiler etc.
73+
Console.WriteLine("Start npm install...");
74+
ProcessHelper.CmdExecute("npm install", targetFilePath);
75+
76+
// run typescript compiler
77+
string tscPath = Path.Combine(targetFilePath, "node_modules", ".bin");
78+
// ToDo: Not sure if this runs under linux/macos
79+
ProcessHelper.CmdExecute(@"tsc -p ../../", tscPath);
80+
81+
// search .csproj
82+
Console.WriteLine($"Search your .csproj to add configure CopyToPublishDirectory to 'Never'");
83+
var projectFile = Directory.EnumerateFiles(currentDirectory, "*.csproj", SearchOption.TopDirectoryOnly).FirstOrDefault();
84+
85+
Console.WriteLine($"Found your .csproj: {projectFile} - check for existing CopyToPublishDirectory setting or update it.");
86+
87+
if (!EditCsProj(projectFile)) return false;
88+
89+
Console.WriteLine($"Everything done - happy electronizing with your custom npm packages!");
90+
91+
return true;
92+
});
93+
}
94+
95+
// ToDo: Cleanup this copy/past code.
96+
private static bool EditCsProj(string projectFile)
97+
{
98+
using (var stream = File.Open(projectFile, FileMode.OpenOrCreate, FileAccess.ReadWrite))
99+
{
100+
var xmlDocument = XDocument.Load(stream);
101+
102+
var projectElement = xmlDocument.Descendants("Project").FirstOrDefault();
103+
if (projectElement == null || projectElement.Attribute("Sdk")?.Value != "Microsoft.NET.Sdk.Web")
104+
{
105+
Console.WriteLine(
106+
$"Project file is not a compatible type of 'Microsoft.NET.Sdk.Web'. Your project: {projectElement?.Attribute("Sdk")?.Value}");
107+
return false;
108+
}
109+
110+
string itemGroupXmlString = "<ItemGroup>" +
111+
"<Content Update=\"ElectronHostHook\\**\\*.*\">" +
112+
"<CopyToPublishDirectory>Never</CopyToPublishDirectory>" +
113+
"</Content>" +
114+
"</ItemGroup>";
115+
116+
var newItemGroupForConfig = XElement.Parse(itemGroupXmlString);
117+
xmlDocument.Root.Add(newItemGroupForConfig);
118+
119+
stream.SetLength(0);
120+
stream.Position = 0;
121+
122+
var xws = new XmlWriterSettings
123+
{
124+
OmitXmlDeclaration = true,
125+
Indent = true
126+
};
127+
using (XmlWriter xw = XmlWriter.Create(stream, xws))
128+
{
129+
xmlDocument.Save(xw);
130+
}
131+
132+
}
133+
134+
Console.WriteLine($"Publish setting added in csproj!");
135+
return true;
136+
}
137+
138+
}
139+
}

ElectronNET.CLI/Commands/BuildCommand.cs

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.IO;
4-
using System.Linq;
54
using System.Runtime.InteropServices;
6-
using System.Text;
75
using System.Threading.Tasks;
86
using ElectronNET.CLI.Commands.Actions;
97

@@ -16,7 +14,7 @@ public class BuildCommand : ICommand
1614
public static string COMMAND_ARGUMENTS = "Needed: '/target' with params 'win/osx/linux' to build for a typical app or use 'custom' and specify .NET Core build config & electron build config" + Environment.NewLine +
1715
" for custom target, check .NET Core RID Catalog and Electron build target/" + Environment.NewLine +
1816
" e.g. '/target win' or '/target custom \"win7-x86;win32\"'" + Environment.NewLine +
19-
"Optional: '/dotnet-configuration' with the desired .NET Core build config e.g. release or debug. Default = Release" + Environment.NewLine +
17+
"Optional: '/dotnet-configuration' with the desired .NET Core build config e.g. release or debug. Default = Release" + Environment.NewLine +
2018
"Optional: '/electron-arch' to specify the resulting electron processor architecture (e.g. ia86 for x86 builds). Be aware to use the '/target custom' param as well!" + Environment.NewLine +
2119
"Optional: '/electron-params' specify any other valid parameter, which will be routed to the electron-packager." + Environment.NewLine +
2220
"Full example for a 32bit debug build with electron prune: build /target custom win7-x86;win32 /dotnet-configuration Debug /electron-arch ia32 /electron-params \"--prune=true \"";
@@ -83,33 +81,40 @@ public Task<bool> ExecuteAsync()
8381
}
8482

8583
DeployEmbeddedElectronFiles.Do(tempPath);
84+
var nodeModulesDirPath = Path.Combine(tempPath, "node_modules");
8685

87-
var checkForNodeModulesDirPath = Path.Combine(tempPath, "node_modules");
86+
Console.WriteLine("Start npm install...");
87+
ProcessHelper.CmdExecute("npm install --production", tempPath);
8888

89-
if (Directory.Exists(checkForNodeModulesDirPath) == false)
89+
Console.WriteLine("Start npm install electron-packager...");
90+
91+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
9092
{
91-
Console.WriteLine("node_modules missing in: " + checkForNodeModulesDirPath);
92-
93-
Console.WriteLine("Start npm install...");
94-
ProcessHelper.CmdExecute("npm install", tempPath);
95-
96-
Console.WriteLine("Start npm install electron-packager...");
97-
98-
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
99-
{
100-
// Works proper on Windows...
101-
ProcessHelper.CmdExecute("npm install electron-packager --global", tempPath);
102-
}
103-
else
104-
{
105-
// ToDo: find another solution or document it proper
106-
// GH Issue https://github.com/electron-userland/electron-prebuilt/issues/48
107-
Console.WriteLine("Electron Packager - make sure you invoke 'sudo npm install electron-packager --global' at " + tempPath + " manually. Sry.");
108-
}
93+
// Works proper on Windows...
94+
ProcessHelper.CmdExecute("npm install electron-packager --global", tempPath);
10995
}
11096
else
11197
{
112-
Console.WriteLine("Skip npm install, because node_modules directory exists in: " + checkForNodeModulesDirPath);
98+
// ToDo: find another solution or document it proper
99+
// GH Issue https://github.com/electron-userland/electron-prebuilt/issues/48
100+
Console.WriteLine("Electron Packager - make sure you invoke 'sudo npm install electron-packager --global' at " + tempPath + " manually. Sry.");
101+
}
102+
103+
Console.WriteLine("ElectronHostHook handling started...");
104+
105+
string electronhosthookDir = Path.Combine(Directory.GetCurrentDirectory(), "ElectronHostHook");
106+
107+
if (Directory.Exists(electronhosthookDir))
108+
{
109+
string hosthookDir = Path.Combine(tempPath, "ElectronHostHook");
110+
DirectoryCopy.Do(electronhosthookDir, hosthookDir, true, new List<string>() { "node_modules" });
111+
112+
Console.WriteLine("Start npm install for hosthooks...");
113+
ProcessHelper.CmdExecute("npm install --production", hosthookDir);
114+
115+
string tscPath = Path.Combine(tempPath, "node_modules", ".bin");
116+
// ToDo: Not sure if this runs under linux/macos
117+
ProcessHelper.CmdExecute(@"tsc -p ../../ElectronHostHook --sourceMap false", tscPath);
113118
}
114119

115120
Console.WriteLine("Build Electron Desktop Application...");

0 commit comments

Comments
 (0)