202 lines
5.6 KiB
C#
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", "*") }
|
|||
|
};
|
|||
|
}
|
|||
|
}
|