public static async Task <int> Run( int interval, bool pullOutlineServer, bool deployOutlineServer, bool generateOnlineConfig, bool regenerateOnlineConfig, CancellationToken cancellationToken = default) { if (interval < 60 || interval > int.MaxValue / 1000) { Console.WriteLine($"Interval can't be shorter than 60 seconds or longer than {int.MaxValue / 1000} seconds."); return(1); } try { while (true) { var(users, loadUsersErrMsg) = await Users.LoadUsersAsync(cancellationToken); if (loadUsersErrMsg is not null) { Console.WriteLine(loadUsersErrMsg); return(1); } var(loadedNodes, loadNodesErrMsg) = await Nodes.LoadNodesAsync(cancellationToken); if (loadNodesErrMsg is not null) { Console.WriteLine(loadNodesErrMsg); return(1); } using var nodes = loadedNodes; var(settings, loadSettingsErrMsg) = await Settings.LoadSettingsAsync(cancellationToken); if (loadSettingsErrMsg is not null) { Console.WriteLine(loadSettingsErrMsg); return(1); } if (pullOutlineServer) { var errMsgs = nodes.PullFromOutlineServerForAllGroups(users, true, cancellationToken); await foreach (var errMsg in errMsgs) { Console.WriteLine(errMsg); } users.CalculateDataUsageForAllUsers(nodes); Console.WriteLine("Pulled from Outline servers."); } if (deployOutlineServer) { var errMsgs = nodes.DeployAllOutlineServers(users, cancellationToken); await foreach (var errMsg in errMsgs) { Console.WriteLine(errMsg); } Console.WriteLine("Deployed to Outline servers."); } if (generateOnlineConfig) { var errMsg = await SIP008StaticGen.GenerateAndSave(users, nodes, settings, cancellationToken); if (errMsg is not null) { Console.Write(errMsg); } Console.WriteLine("Generated online config."); } if (regenerateOnlineConfig) { SIP008StaticGen.Remove(users, settings); Console.WriteLine("Cleaned online config."); var errMsg = await SIP008StaticGen.GenerateAndSave(users, nodes, settings, cancellationToken); if (errMsg is not null) { Console.Write(errMsg); } Console.WriteLine("Generated online config."); } var saveUsersErrMsg = await Users.SaveUsersAsync(users, cancellationToken); if (saveUsersErrMsg is not null) { Console.WriteLine(saveUsersErrMsg); return(1); } var saveNodesErrMsg = await Nodes.SaveNodesAsync(nodes, cancellationToken); if (saveNodesErrMsg is not null) { Console.WriteLine(saveNodesErrMsg); return(1); } await Task.Delay(interval * 1000, cancellationToken); } } catch (OperationCanceledException) // Task.Delay() canceled { } catch (Exception ex) // other unhandled { Console.WriteLine($"An error occurred while executing one of the scheduled tasks: {ex.Message}"); return(-1); } return(0); }
public static async Task <int> Remove(string[] usernames, CancellationToken cancellationToken = default) { var commandResult = 0; var(users, loadUsersErrMsg) = await Users.LoadUsersAsync(cancellationToken); if (loadUsersErrMsg is not null) { Console.WriteLine(loadUsersErrMsg); return(1); } var(loadedNodes, loadNodesErrMsg) = await Nodes.LoadNodesAsync(cancellationToken); if (loadNodesErrMsg is not null) { Console.WriteLine(loadNodesErrMsg); return(1); } using var nodes = loadedNodes; var(settings, loadSettingsErrMsg) = await Settings.LoadSettingsAsync(cancellationToken); if (loadSettingsErrMsg is not null) { Console.WriteLine(loadSettingsErrMsg); return(1); } // Removing online config requires reading user entry. if (settings.OnlineConfigCleanOnUserRemoval) { SIP008StaticGen.Remove(users, settings, usernames); } // Remove user entry. foreach (var username in usernames) { if (users.UserDict.TryGetValue(username, out var user)) { // Clear group and node ownership. var ownedGroupEntries = nodes.Groups.Where(x => x.Value.OwnerUuid == user.Uuid); var ownedNodeEntries = nodes.Groups.SelectMany(x => x.Value.NodeDict) .Where(x => x.Value.OwnerUuid == user.Uuid); foreach (var groupEntry in ownedGroupEntries) { groupEntry.Value.OwnerUuid = null; Console.WriteLine($"{username}: Disowned group {groupEntry.Key}."); } foreach (var nodeEntry in ownedNodeEntries) { nodeEntry.Value.OwnerUuid = null; Console.WriteLine($"{username}: Disowned node {nodeEntry.Key}."); } _ = users.RemoveUser(username); Console.WriteLine($"Removed user {username}."); } else { commandResult--; Console.WriteLine($"Error: User {username} doesn't exist."); } } var saveUsersErrMsg = await Users.SaveUsersAsync(users, cancellationToken); if (saveUsersErrMsg is not null) { Console.WriteLine(saveUsersErrMsg); return(1); } return(commandResult); }
public async Task Save_Clean_OnlineConfig_ForAllUsers() { var settings = new Settings(); var directory = FileHelper.GetAbsolutePath(settings.OnlineConfigOutputDirectory); using var nodes = new Nodes(); nodes.AddGroup("MyGroup"); nodes.AddGroup("MyGroupWithPlugin"); nodes.AddNodeToGroup("MyGroup", "MyNode", "github.com", 443); nodes.AddNodeToGroup("MyGroupWithPlugin", "MyNodeWithPlugin", "github.com", 443, "v2ray-plugin", "server;tls;host=github.com"); var users = new Users(); users.AddUser("root"); users.AddUser("http"); users.AddUser("nobody"); users.AddCredentialToUser("root", "MyGroup", "Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTp5bWdoaVIjNzVUTnFwYQ"); users.AddCredentialToUser("http", "MyGroupWithPlugin", "aes-256-gcm", "wLhN2STZ"); var rootUser = users.UserDict["root"]; var httpUser = users.UserDict["http"]; var nobodyUser = users.UserDict["nobody"]; // Disable delivery by group settings.OnlineConfigDeliverByGroup = false; // Save var genResult = await SIP008StaticGen.GenerateAndSave(users, nodes, settings); Assert.Null(genResult); Assert.True(Directory.Exists(directory)); foreach (var user in users.UserDict.Values) { Assert.True(File.Exists($"{directory}/{user.Uuid}.json")); } // Clean SIP008StaticGen.Remove(users, settings); Assert.True(Directory.Exists(directory)); foreach (var user in users.UserDict.Values) { Assert.False(File.Exists($"{directory}/{user.Uuid}.json")); } // Delete working directory. Directory.Delete(directory); // Enable delivery by group settings.OnlineConfigDeliverByGroup = true; // Save var genByGroupResult = await SIP008StaticGen.GenerateAndSave(users, nodes, settings); Assert.Null(genByGroupResult); Assert.True(Directory.Exists(directory)); foreach (var user in users.UserDict.Values) { Assert.True(File.Exists($"{directory}/{user.Uuid}.json")); } Assert.True(Directory.Exists($"{directory}/{rootUser.Uuid}")); Assert.True(File.Exists($"{directory}/{rootUser.Uuid}/MyGroup.json")); Assert.False(File.Exists($"{directory}/{rootUser.Uuid}/MyGroupWithPlugin.json")); Assert.True(Directory.Exists($"{directory}/{httpUser.Uuid}")); Assert.False(File.Exists($"{directory}/{httpUser.Uuid}/MyGroup.json")); Assert.True(File.Exists($"{directory}/{httpUser.Uuid}/MyGroupWithPlugin.json")); Assert.False(Directory.Exists($"{directory}/{nobodyUser.Uuid}")); // Clean SIP008StaticGen.Remove(users, settings); Assert.True(Directory.Exists(directory)); foreach (var user in users.UserDict.Values) { Assert.False(File.Exists($"{directory}/{user.Uuid}.json")); } Assert.False(Directory.Exists($"{directory}/{rootUser.Uuid}")); Assert.False(Directory.Exists($"{directory}/{httpUser.Uuid}")); Assert.False(Directory.Exists($"{directory}/{nobodyUser.Uuid}")); // Delete working directory. Directory.Delete(directory); }