Refactor IPC

This commit is contained in:
Natsumi
2023-03-07 01:09:01 +13:00
parent 18aa24fa60
commit bb8c3dcfa9
8 changed files with 151 additions and 38 deletions

View File

@@ -9,7 +9,6 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.IO.Pipes;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
@@ -346,12 +345,20 @@ namespace VRCX
public void IPCAnnounceStart() public void IPCAnnounceStart()
{ {
var ipcClient = new NamedPipeClientStream(".", "vrcx-ipc", PipeDirection.InOut); IPCServer.Send(new IPCPacket
ipcClient.Connect(); {
if (!ipcClient.IsConnected) Type = "VRCXLaunch"
return; });
var buffer = Encoding.UTF8.GetBytes("{\"type\":\"VRCXLaunch\"}" + (char)0x00); }
ipcClient.BeginWrite(buffer, 0, buffer.Length, IPCClient.OnSend, ipcClient);
public void SendIpc(string type, string data)
{
IPCServer.Send(new IPCPacket
{
Type = "VrcxMessage",
MsgType = type,
Data = data
});
} }
public void ExecuteAppFunction(string function, string json) public void ExecuteAppFunction(string function, string json)

View File

@@ -4,23 +4,33 @@
// This work is licensed under the terms of the MIT license. // This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>. // For a copy, see <https://opensource.org/licenses/MIT>.
using CefSharp;
using Newtonsoft.Json;
using System; using System;
using System.Collections.Generic; using System.Globalization;
using System.IO;
using System.IO.Pipes; using System.IO.Pipes;
using System.Text; using System.Text;
using System.Threading.Tasks;
using CefSharp;
using Newtonsoft.Json;
namespace VRCX namespace VRCX
{ {
internal class IPCClient internal class IPCClient
{ {
private NamedPipeServerStream _ipcServer; private static readonly UTF8Encoding noBomEncoding = new UTF8Encoding(false, false);
private byte[] _recvBuffer = new byte[1024 * 8]; private readonly NamedPipeServerStream _ipcServer;
private readonly byte[] _recvBuffer = new byte[1024 * 8];
private readonly MemoryStream memoryStream;
private readonly byte[] packetBuffer = new byte[1024 * 1024];
private readonly Newtonsoft.Json.JsonSerializer serializer = new Newtonsoft.Json.JsonSerializer();
private string _currentPacket; private string _currentPacket;
public IPCClient(NamedPipeServerStream ipcServer) public IPCClient(NamedPipeServerStream ipcServer)
{ {
memoryStream = new MemoryStream(packetBuffer);
serializer.Culture = CultureInfo.InvariantCulture;
serializer.Formatting = Formatting.None;
_ipcServer = ipcServer; _ipcServer = ipcServer;
} }
@@ -29,6 +39,28 @@ namespace VRCX
_ipcServer.BeginRead(_recvBuffer, 0, _recvBuffer.Length, OnRead, _ipcServer); _ipcServer.BeginRead(_recvBuffer, 0, _recvBuffer.Length, OnRead, _ipcServer);
} }
public async Task Send(IPCPacket ipcPacket)
{
try
{
memoryStream.Seek(0, SeekOrigin.Begin);
using (var streamWriter = new StreamWriter(memoryStream, noBomEncoding, 65535, true))
using (var writer = new JsonTextWriter(streamWriter))
{
serializer.Serialize(writer, ipcPacket);
streamWriter.Write((char)0x00);
streamWriter.Flush();
}
var length = (int)memoryStream.Position;
_ipcServer?.BeginWrite(packetBuffer, 0, length, OnSend, null);
}
catch
{
IPCServer.Clients.Remove(this);
}
}
private void OnRead(IAsyncResult asyncResult) private void OnRead(IAsyncResult asyncResult)
{ {
try try
@@ -37,6 +69,7 @@ namespace VRCX
if (bytesRead <= 0) if (bytesRead <= 0)
{ {
IPCServer.Clients.Remove(this);
_ipcServer.Close(); _ipcServer.Close();
return; return;
} }
@@ -69,7 +102,14 @@ namespace VRCX
public static void OnSend(IAsyncResult asyncResult) public static void OnSend(IAsyncResult asyncResult)
{ {
var ipcClient = (NamedPipeClientStream)asyncResult.AsyncState; var ipcClient = (NamedPipeClientStream)asyncResult.AsyncState;
ipcClient.EndWrite(asyncResult); ipcClient?.EndWrite(asyncResult);
}
public static void Close(IAsyncResult asyncResult)
{
var ipcClient = (NamedPipeClientStream)asyncResult.AsyncState;
ipcClient?.EndWrite(asyncResult);
ipcClient?.Close();
} }
} }
} }

9
IPCPacket.cs Normal file
View File

@@ -0,0 +1,9 @@
namespace VRCX
{
public class IPCPacket
{
public string Type { get; set; }
public string Data { get; set; }
public string MsgType { get; set; }
}
}

View File

@@ -5,13 +5,16 @@
// For a copy, see <https://opensource.org/licenses/MIT>. // For a copy, see <https://opensource.org/licenses/MIT>.
using System; using System;
using System.Collections.Generic;
using System.IO.Pipes; using System.IO.Pipes;
using System.Threading.Tasks;
namespace VRCX namespace VRCX
{ {
class IPCServer internal class IPCServer
{ {
public static readonly IPCServer Instance; public static readonly IPCServer Instance;
public static readonly List<IPCClient> Clients = new List<IPCClient>();
static IPCServer() static IPCServer()
{ {
@@ -23,10 +26,18 @@ namespace VRCX
new IPCServer().CreateIPCServer(); new IPCServer().CreateIPCServer();
} }
public static async Task Send(IPCPacket ipcPacket)
{
foreach (var client in Clients)
{
await client.Send(ipcPacket);
}
}
public void CreateIPCServer() public void CreateIPCServer()
{ {
var ipcServer = new NamedPipeServerStream("vrcx-ipc", PipeDirection.InOut, NamedPipeServerStream.MaxAllowedServerInstances, PipeTransmissionMode.Byte, PipeOptions.Asynchronous); var ipcServer = new NamedPipeServerStream("vrcx-ipc", PipeDirection.InOut, NamedPipeServerStream.MaxAllowedServerInstances, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
ipcServer.BeginWaitForConnection(asyncResult => DoAccept(asyncResult), ipcServer); ipcServer.BeginWaitForConnection(DoAccept, ipcServer);
} }
private void DoAccept(IAsyncResult asyncResult) private void DoAccept(IAsyncResult asyncResult)
@@ -42,7 +53,9 @@ namespace VRCX
Console.WriteLine(e); Console.WriteLine(e);
} }
new IPCClient(ipcServer).BeginRead(); var ipcClient = new IPCClient(ipcServer);
Clients.Add(ipcClient);
ipcClient.BeginRead();
CreateIPCServer(); CreateIPCServer();
} }
} }

View File

@@ -19,13 +19,13 @@ namespace VRCX
public static void ArgsCheck() public static void ArgsCheck()
{ {
string[] args = Environment.GetCommandLineArgs(); var args = Environment.GetCommandLineArgs();
processList = Process.GetProcessesByName("VRCX"); processList = Process.GetProcessesByName("VRCX");
bool isDebug = false; var isDebug = false;
Debug.Assert(isDebug = true); Debug.Assert(isDebug = true);
foreach (string arg in args) foreach (var arg in args)
{ {
if (arg.Contains("--gpufix")) if (arg.Contains("--gpufix"))
Program.GPUFix = true; Program.GPUFix = true;
@@ -40,7 +40,7 @@ namespace VRCX
Program.LaunchDebug = true; Program.LaunchDebug = true;
} }
if (processList.Length > 1 && String.IsNullOrEmpty(LaunchCommand)) if (processList.Length > 1 && string.IsNullOrEmpty(LaunchCommand))
{ {
var result = MessageBox.Show("VRCX is already running, start another instance?", "VRCX", MessageBoxButtons.YesNo, MessageBoxIcon.Question); var result = MessageBox.Show("VRCX is already running, start another instance?", "VRCX", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (result == DialogResult.Yes) if (result == DialogResult.Yes)
@@ -63,7 +63,7 @@ namespace VRCX
if (ipcClient.IsConnected) if (ipcClient.IsConnected)
{ {
var buffer = Encoding.UTF8.GetBytes($"{{\"type\":\"LaunchCommand\",\"command\":\"{LaunchCommand}\"}}" + (char)0x00); var buffer = Encoding.UTF8.GetBytes($"{{\"type\":\"LaunchCommand\",\"command\":\"{LaunchCommand}\"}}" + (char)0x00);
ipcClient.BeginWrite(buffer, 0, buffer.Length, IPCClient.OnSend, ipcClient); ipcClient.BeginWrite(buffer, 0, buffer.Length, IPCClient.Close, ipcClient);
} }
} }
} }

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup> <PropertyGroup>
@@ -160,6 +160,7 @@
<None Include="App.config" /> <None Include="App.config" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="IPCPacket.cs" />
<Content Include="VRCX.ico"> <Content Include="VRCX.ico">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>

View File

@@ -2583,7 +2583,15 @@ speechSynthesis.getVoices();
}; };
this.cachedAvatars.set(ref.id, ref); this.cachedAvatars.set(ref.id, ref);
} else { } else {
var {unityPackages} = ref;
Object.assign(ref, json); Object.assign(ref, json);
if (
json.unityPackages.length > 0 &&
unityPackages.length > 0 &&
!json.unityPackages.assetUrl
) {
ref.unityPackages = unityPackages;
}
} }
ref.name = $app.replaceBioSymbols(ref.name); ref.name = $app.replaceBioSymbols(ref.name);
ref.description = $app.replaceBioSymbols(ref.description); ref.description = $app.replaceBioSymbols(ref.description);
@@ -10774,10 +10782,24 @@ speechSynthesis.getVoices();
} }
if (block === row.block && mute === row.mute) { if (block === row.block && mute === row.mute) {
// no change // no change
type = ''; if (type) {
this.addEntryPhotonEvent({
photonId,
text: `Moderation ${text}`,
type: 'Moderation',
color: 'yellow',
created_at: gameLogDate
});
}
return;
} }
} }
if (text) { this.moderationAgainstTable.forEach((item) => {
if (item.userId === ref.id && item.type === type) {
removeFromArray(this.moderationAgainstTable, item);
}
});
if (type) {
this.addEntryPhotonEvent({ this.addEntryPhotonEvent({
photonId, photonId,
text: `Moderation ${text}`, text: `Moderation ${text}`,
@@ -10785,8 +10807,6 @@ speechSynthesis.getVoices();
color: 'yellow', color: 'yellow',
created_at: gameLogDate created_at: gameLogDate
}); });
}
if (type) {
var noty = { var noty = {
created_at: new Date().toJSON(), created_at: new Date().toJSON(),
userId: ref.id, userId: ref.id,
@@ -10800,12 +10820,9 @@ speechSynthesis.getVoices();
displayName: ref.displayName, displayName: ref.displayName,
type type
}; };
this.moderationAgainstTable.forEach((item) => {
if (item.userId === ref.id && item.type === type) {
removeFromArray(this.moderationAgainstTable, item);
}
});
this.moderationAgainstTable.push(entry); this.moderationAgainstTable.push(entry);
}
if (block || mute || block !== row.block || mute !== row.mute) {
this.updateSharedFeed(true); this.updateSharedFeed(true);
} }
if (block || mute) { if (block || mute) {
@@ -10816,7 +10833,7 @@ speechSynthesis.getVoices();
block, block,
mute mute
}); });
} else { } else if (row.block || row.mute) {
database.deleteModeration(ref.id); database.deleteModeration(ref.id);
} }
}); });
@@ -14875,6 +14892,9 @@ speechSynthesis.getVoices();
} }
); );
} }
if (this.ipcEnabled) {
AppApi.SendIpc('ShowUserDialog', userId);
}
API.getCachedUser({ API.getCachedUser({
userId userId
}) })
@@ -21617,6 +21637,8 @@ speechSynthesis.getVoices();
this.ipcEnabled = true; this.ipcEnabled = true;
this.ipcTimeout = 60; // 30secs this.ipcTimeout = 60; // 30secs
break; break;
case 'MsgPing':
break;
case 'LaunchCommand': case 'LaunchCommand':
AppApi.FocusWindow(); AppApi.FocusWindow();
this.eventLaunchCommand(data.command); this.eventLaunchCommand(data.command);
@@ -21644,10 +21666,22 @@ speechSynthesis.getVoices();
$app.data.customUserTags = new Map(); $app.data.customUserTags = new Map();
$app.methods.addCustomTag = function (data) { $app.methods.addCustomTag = function (data) {
this.customUserTags.set(data.UserId, { if (data.Tag) {
tag: data.Tag, this.customUserTags.set(data.UserId, {
tag: data.Tag,
colour: data.TagColour
});
} else {
this.customUserTags.delete(data.UserId);
}
var feedUpdate = {
userId: data.UserId,
colour: data.TagColour colour: data.TagColour
}); };
AppApi.ExecuteVrOverlayFunction(
'updateHudFeedTag',
JSON.stringify(feedUpdate)
);
var ref = API.cachedUsers.get(data.UserId); var ref = API.cachedUsers.get(data.UserId);
if (typeof ref !== 'undefined') { if (typeof ref !== 'undefined') {
ref.$customTag = data.Tag; ref.$customTag = data.Tag;

View File

@@ -726,6 +726,15 @@ Vue.component('marquee-text', MarqueeText);
this.cleanHudFeed(); this.cleanHudFeed();
}; };
$app.methods.updateHudFeedTag = function (json) {
var ref = JSON.parse(json);
this.hudFeed.forEach((item) => {
if (item.userId === ref.userId) {
item.colour = ref.colour;
}
});
};
$app.data.hudTimeout = []; $app.data.hudTimeout = [];
$app.methods.updateHudTimeout = function (json) { $app.methods.updateHudTimeout = function (json) {