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

View File

@@ -4,23 +4,33 @@
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
using CefSharp;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.IO.Pipes;
using System.Text;
using System.Threading.Tasks;
using CefSharp;
using Newtonsoft.Json;
namespace VRCX
{
internal class IPCClient
{
private NamedPipeServerStream _ipcServer;
private byte[] _recvBuffer = new byte[1024 * 8];
private static readonly UTF8Encoding noBomEncoding = new UTF8Encoding(false, false);
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;
public IPCClient(NamedPipeServerStream ipcServer)
{
memoryStream = new MemoryStream(packetBuffer);
serializer.Culture = CultureInfo.InvariantCulture;
serializer.Formatting = Formatting.None;
_ipcServer = ipcServer;
}
@@ -29,6 +39,28 @@ namespace VRCX
_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)
{
try
@@ -37,6 +69,7 @@ namespace VRCX
if (bytesRead <= 0)
{
IPCServer.Clients.Remove(this);
_ipcServer.Close();
return;
}
@@ -69,7 +102,14 @@ namespace VRCX
public static void OnSend(IAsyncResult asyncResult)
{
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>.
using System;
using System.Collections.Generic;
using System.IO.Pipes;
using System.Threading.Tasks;
namespace VRCX
{
class IPCServer
internal class IPCServer
{
public static readonly IPCServer Instance;
public static readonly List<IPCClient> Clients = new List<IPCClient>();
static IPCServer()
{
@@ -23,10 +26,18 @@ namespace VRCX
new IPCServer().CreateIPCServer();
}
public static async Task Send(IPCPacket ipcPacket)
{
foreach (var client in Clients)
{
await client.Send(ipcPacket);
}
}
public void CreateIPCServer()
{
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)
@@ -42,8 +53,10 @@ namespace VRCX
Console.WriteLine(e);
}
new IPCClient(ipcServer).BeginRead();
var ipcClient = new IPCClient(ipcServer);
Clients.Add(ipcClient);
ipcClient.BeginRead();
CreateIPCServer();
}
}
}
}

View File

@@ -19,17 +19,17 @@ namespace VRCX
public static void ArgsCheck()
{
string[] args = Environment.GetCommandLineArgs();
var args = Environment.GetCommandLineArgs();
processList = Process.GetProcessesByName("VRCX");
bool isDebug = false;
var isDebug = false;
Debug.Assert(isDebug = true);
foreach (string arg in args)
foreach (var arg in args)
{
if (arg.Contains("--gpufix"))
Program.GPUFix = true;
if (arg.Length > 12 && arg.Substring(0, 12) == "/uri=vrcx://")
LaunchCommand = arg.Substring(12);
@@ -40,7 +40,7 @@ namespace VRCX
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);
if (result == DialogResult.Yes)
@@ -63,7 +63,7 @@ namespace VRCX
if (ipcClient.IsConnected)
{
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">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
@@ -160,6 +160,7 @@
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<Compile Include="IPCPacket.cs" />
<Content Include="VRCX.ico">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>

View File

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

View File

@@ -726,6 +726,15 @@ Vue.component('marquee-text', MarqueeText);
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.methods.updateHudTimeout = function (json) {