Innovenergy_trunk/csharp/app/API/Program.cs

202 lines
5.6 KiB
C#

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<String, LoginState> LoggedInUsers { get; } = new Dictionary<String, LoginState>();
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>(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", "*") }
};
}
}