using Flurl; using InnovEnergy.API.DataModel; using InnovEnergy.Lib.WebServer; using InnovEnergy.Lib.Utils; using Newtonsoft.Json; using static System.Text.Encoding; using static InnovEnergy.Lib.WebServer.Default; namespace InnovEnergy.API; public static class Program { public static String RootDir { get; private set; } = "/home/eef/sync/work/Code/innovenergy/server/WebMonitoring/src"; public static Data Data { get; set; } public static Dictionary LoggedInUsers { get; } = new Dictionary(); public static void Main(String[] args) { RootDir = args.FirstOrDefault() ?? RootDir; Console.WriteLine("start"); #pragma warning disable 4014 SyncWithVrm(); #pragma warning restore 4014 Data = Data.Load(); WebServer.ServeOnLocalHost(8080, Serve); Console.WriteLine("stop"); } private static async Task SyncWithVrm() { Console.WriteLine("Starting VRM sync"); var vrmLink = await VrmLink.Login(); while (true) { try { var data = Data.Load(); var json = data.SerializeJson(); await vrmLink.SyncWithVrm(data); var changed = json != data.SerializeJson(); if (changed) { data.Save("Synced from VRM", "system"); var edit = data.Edit; Console.WriteLine($"{edit.TimeStamp} [{edit.Version}] {edit.Action}"); Data = data; } await Task.Delay(TimeSpan.FromMinutes(10)); } catch (Exception e) { Console.WriteLine("Failed to sync with VRM:\n" + e); } } } public static HttpResponse Serve(HttpRequest request) { var pathSegments = request.Url.PathSegments; var p0 = pathSegments.ElementAtOrDefault(0); Console.WriteLine(p0); return p0 switch { "api" => ServeApi(request), _ => ServeAssets(request) }; } private static HttpResponse Login(QueryParamCollection query) { var userName = query.FirstOrDefault("username") as String; var password = query.FirstOrDefault("password") as String; // TODO: password check if (String.IsNullOrEmpty(userName)) return HttpForbidden; var userPath = Data.Root.FindDescendantUser(userName); var user = userPath?.User(); var homeFolder = userPath?.Parent.Folder(); if (user is null || homeFolder is null) return HttpForbidden; var loginState = new LoginState(user, homeFolder, Data.Edit.Version); LoggedInUsers[loginState.Token] = loginState; // TODO: remove stale tokens return CreateJsonResponse(loginState); } private static HttpResponse ServeApi(HttpRequest request) { var url = request.Url; var query = url.QueryParams; var action = query.FirstOrDefault("action") as String; Console.WriteLine(action); if (action == "login") return Login(query); if (query.FirstOrDefault("token") is not String token || !LoggedInUsers.TryGetValue(token, out var loginState)) return HttpForbidden; var result = action switch { "createUser" => Api.CreateUser(query, loginState), "editUser" => Api.EditUser(query, loginState), "renameInstallation" => Api.RenameInstallation(query, loginState), // "deleteUser" => Api.DeleteUser(query, loginState), // "deleteFolder" => Api.DeleteFolder(query, loginState), // "deleteInstallation" => Api.DeleteInstallation(query, loginState), //"rename" => Api.Delete(query, loginState), _ => Result.Failure("unsupported api call") }; return result .WriteToDisk(loginState.LoginUser) .CreateResponse(loginState); } private static HttpResponse ServeAssets(HttpRequest request) { var localPath = RootDir + request.Url.Path; if (request.Url.PathSegments.Count == 0) localPath = RootDir + "/index.html"; Console.WriteLine(request.Url + " => " + localPath + " | " + InferContentType.FromExtension(localPath)); if (!File.Exists(localPath)) { Console.WriteLine("404"); return HttpNotFound; } return new HttpResponse { Content = File.ReadAllBytes(localPath), // TODO: cache? ContentType = InferContentType.FromExtension(localPath) }; } private static Result WriteToDisk(this Result result, User loggedInUser) { if (result.Succeeded) { Data.Save(result.Message, loggedInUser.Name); } return result; } private static HttpResponse CreateResponse(this Result result, LoginState loginState) { loginState.DataVersion = Data.Edit.Version; // important! loginState.Error = result.Succeeded ? null : result.Message; return CreateJsonResponse(loginState); } private static HttpResponse CreateJsonResponse(T payload) { var json = JsonConvert.SerializeObject(payload, Data.WireFormatJsonSettings); return new HttpResponse { Content = json.Apply(UTF8.GetBytes), ContentType = ContentType.ApplicationJson, Headers = new[] { new HttpHeader("Access-Control-Allow-Origin", "*") } }; } }