Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor and fixes #5

Merged
merged 1 commit into from
Jul 24, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
259 changes: 143 additions & 116 deletions ADBForwarder/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System.Linq;
using System.Net;
using System.Threading;
using System.Diagnostics;
using System.Net.Http;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
Expand All @@ -13,161 +12,189 @@
using Microsoft.Extensions.Configuration;
using UnixFileMode = System.IO.UnixFileMode;

namespace ADBForwarder
namespace ADBForwarder;

internal class PortConfiguration(List<int> ports)
{
internal class PortConfiguration(List<int> ports)
{
public List<int> Ports { get; set; } = ports;
}
public List<int> Ports { get; set; } = ports;
}

internal static class Program
{
private static readonly AdbClient Client = new();
private static readonly AdbServer Server = new();
private static readonly IPEndPoint EndPoint = new(IPAddress.Loopback, AdbClient.AdbServerPort);
private static PortConfiguration _portConfiguration;

internal static class Program
private static void Main()
{
private static readonly AdbClient Client = new();
private static readonly AdbServer Server = new();
private static readonly IPEndPoint EndPoint = new(IPAddress.Loopback, AdbClient.AdbServerPort);
private static PortConfiguration _portConfiguration;
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("config.json", optional: true);

private static void Main()
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("config.json", optional: true);
IConfiguration config = builder.Build();

IConfiguration config = builder.Build();
_portConfiguration = config.GetSection("PortConfiguration").Get<PortConfiguration>()
?? new PortConfiguration([9943, 9944]);

_portConfiguration = config.GetSection("PortConfiguration").Get<PortConfiguration>()
?? new PortConfiguration([9943, 9944]);
Console.ResetColor();
var currentDirectory = Path.GetDirectoryName(AppContext.BaseDirectory);
if (currentDirectory == null)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Path error!");
return;
}

Console.ResetColor();
var currentDirectory = Path.GetDirectoryName(AppContext.BaseDirectory);
if (currentDirectory == null)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Path error!");
return;
}
var adbFolderPath = Path.Combine(currentDirectory, "adb");
var adbPath = Path.Combine(adbFolderPath, "platform-tools");
var downloadUri = "https://dl.google.com/android/repository/platform-tools-latest-{0}.zip";

var adbPath = "adb/platform-tools/{0}";
var downloadUri = "https://dl.google.com/android/repository/platform-tools-latest-{0}.zip";
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
Console.WriteLine("Platform: Linux");

if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
Console.WriteLine("Platform: Linux");
adbPath = Path.Combine(adbPath, "adb");
downloadUri = string.Format(downloadUri, "linux");
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
Console.WriteLine("Platform: Windows");

adbPath = string.Format(adbPath, "adb");
downloadUri = string.Format(downloadUri, "linux");
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
Console.WriteLine("Platform: Windows");
adbPath = Path.Combine(adbPath, "adb.exe");
downloadUri = string.Format(downloadUri, "windows");
}
else
{
Console.WriteLine("Unsupported platform!");
return;
}

adbPath = string.Format(adbPath, "adb.exe");
downloadUri = string.Format(downloadUri, "windows");
}
else
{
Console.WriteLine("Unsupported platform!");
return;
}
var absoluteAdbPath = Path.Combine(currentDirectory, adbPath);
if (!File.Exists(absoluteAdbPath))
{
Console.WriteLine("ADB not found, downloading...");
DownloadAdb(adbFolderPath, downloadUri).Wait();

var absoluteAdbPath = Path.Combine(currentDirectory, adbPath);
if (!File.Exists(absoluteAdbPath))
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
Console.WriteLine("ADB not found, downloading...");
DownloadADB(downloadUri).Wait();

if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
Console.WriteLine("Giving adb executable permissions");
File.SetUnixFileMode(absoluteAdbPath,
UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute);
}
Console.WriteLine("Giving adb executable permissions");
File.SetUnixFileMode(absoluteAdbPath,
UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute);
}
}

Console.WriteLine("Starting ADB Server...");
Server.StartServer(absoluteAdbPath, false);
Server.StartServer(absoluteAdbPath, false);

Client.Connect(EndPoint);
Client.Connect(EndPoint);

var monitor = new DeviceMonitor(new AdbSocket(EndPoint));
monitor.DeviceConnected += Monitor_DeviceConnected;
monitor.DeviceDisconnected += Monitor_DeviceDisconnected;
monitor.Start();
Console.WriteLine("Adb server started.");
Console.WriteLine("If your device doesn't show up after connecting the device, " +
"please make sure dev mode is enabled on headset and cable or usb port is not damaged.");

while (true)
{
// Main thread needs to stay alive, 100ms is acceptable idle time
Thread.Sleep(100);
}
}
var monitor = new DeviceMonitor(new AdbSocket(EndPoint));
monitor.DeviceConnected += Monitor_DeviceConnected;
monitor.DeviceDisconnected += Monitor_DeviceDisconnected;
monitor.Start();

private static void Monitor_DeviceConnected(object sender, DeviceDataEventArgs e)
while (true)
{
// Prevent duplicate ports
_portConfiguration.Ports = _portConfiguration.Ports.Distinct().ToList();
if (e.Device.Serial.StartsWith("127.0.0.1"))
{
// We don't want to re-forward local device
return;
}

Console.ForegroundColor = ConsoleColor.DarkGreen;
Console.WriteLine($"Connected device: {e.Device.Serial}");
Forward(e.Device);
// Main thread needs to stay alive, 100ms is acceptable idle time
Thread.Sleep(100);
}
}

private static void Monitor_DeviceDisconnected(object sender, DeviceDataEventArgs e)
private static void Monitor_DeviceConnected(object sender, DeviceDataEventArgs e)
{
// Prevent duplicate ports
_portConfiguration.Ports = _portConfiguration.Ports.Distinct().ToList();
if (e.Device.Serial.StartsWith("127.0.0.1"))
{
Console.ForegroundColor = ConsoleColor.DarkRed;
Console.WriteLine($"Disconnected device: {e.Device.Serial}");
// We don't want to re-forward local device
return;
}

private static void Forward(DeviceData device)
{
// DeviceConnected calls without product set yet
Thread.Sleep(1000);
Console.ForegroundColor = ConsoleColor.DarkGreen;
Console.WriteLine($"Connected device: {DeviceStringFromDeviceData(e.Device)}");
Forward(e.Device);
}

foreach (var deviceData in Client.GetDevices().Where(deviceData => device.Serial == deviceData.Serial))
private static void Monitor_DeviceDisconnected(object sender, DeviceDataEventArgs e)
{
Console.ForegroundColor = ConsoleColor.DarkRed;
Console.WriteLine($"Disconnected device: {DeviceStringFromDeviceData(e.Device)}");
}

private static void Forward(DeviceData device)
{
// DeviceConnected calls without product set yet
Thread.Sleep(1000);

foreach (var deviceData in Client.GetDevices().Where(deviceData => device.Serial == deviceData.Serial))
{
if (deviceData.State != DeviceState.Online)
{
if (deviceData.State != DeviceState.Online)
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("Skipped forwarding device: " +
$"{DeviceStringFromDeviceData(deviceData)}," +
$" Error: {deviceData.State}");

if (deviceData.State == DeviceState.Unauthorized)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine(
$"Skipped forwarding device: {(string.IsNullOrEmpty(deviceData.Product) ? deviceData.Serial : deviceData.Product)}");
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) return;
Console.WriteLine("Please make sure you have android-udev-rules installed.");
Console.WriteLine("Install them through package manager or visit https://github.com/M0Rf30/android-udev-rules and follow instructions.");
Console.WriteLine("Unauthorized device, please make sure you enabled developer mode on device, " +
"authorized adb connection on the device and then replug usb cable.");
Console.ForegroundColor = ConsoleColor.White;
return;
}

foreach (var port in _portConfiguration.Ports)
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
Client.CreateForward(deviceData, port, port);
Console.WriteLine("Permission error, please make sure you have " +
"android-udev-rules installed and reboot pc.");
Console.WriteLine("Install udev rules through package manager or visit " +
"https://github.com/M0Rf30/android-udev-rules and follow instructions.");
Console.ForegroundColor = ConsoleColor.White;
return;
}

Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine($"Successfully forwarded device: {deviceData.Serial} [{deviceData.Product}]");

return;
}
}

private static async Task DownloadADB(string downloadUri)
{
using var client = new HttpClient();
var fileStream = await client.GetStreamAsync(downloadUri);
await using (var outputFileStream = new FileStream("adb.zip", FileMode.Create))
foreach (var port in _portConfiguration.Ports)
{
await fileStream.CopyToAsync(outputFileStream);
Client.CreateForward(deviceData, port, port);
}

Console.WriteLine("Download successful");
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine($"Successfully forwarded device: {DeviceStringFromDeviceData(deviceData)}");
Console.ForegroundColor = ConsoleColor.White;

var zip = new FastZip();
zip.ExtractZip("adb.zip", "adb", null);
Console.WriteLine("Extraction successful");
return;
}
}

File.Delete("adb.zip");
private static string DeviceStringFromDeviceData(DeviceData deviceData)
{
return string.IsNullOrWhiteSpace(deviceData.Product)
? deviceData.Serial
: $"{deviceData.Serial} [{deviceData.Product}]";
}

private static async Task DownloadAdb(string adbFolderPath, string downloadUri)
{
using var client = new HttpClient();
var fileStream = await client.GetStreamAsync(downloadUri);
Directory.CreateDirectory(adbFolderPath);
var zipPath = Path.Combine(adbFolderPath, "adb.zip");
await using (var outputFileStream = new FileStream(zipPath, FileMode.Create))
{
await fileStream.CopyToAsync(outputFileStream);
}

Console.WriteLine("Download successful");

var zip = new FastZip();
zip.ExtractZip(zipPath, adbFolderPath, null);
Console.WriteLine("Extraction successful");

File.Delete(zipPath);
}
}
Loading