mirror of
https://github.com/vrcx-team/VRCX.git
synced 2026-04-06 00:32:02 +02:00
Refactor IPC
This commit is contained in:
21
AppApi.cs
21
AppApi.cs
@@ -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)
|
||||
|
||||
52
IPCClient.cs
52
IPCClient.cs
@@ -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
9
IPCPacket.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
21
IPCServer.cs
21
IPCServer.cs
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user