Commit 8970e319 authored by Ing. Jiří Fryč's avatar Ing. Jiří Fryč

🥇 Init commit.

parents
/bin
/obj
/temp
using KazetaNode.Coms;
using KazetaNode.Libraries;
using System;
using System.Collections.Generic;
using System.Text;
namespace KazetaNode
{
abstract class Command
{
public abstract string[] Aliases { get; }
public abstract void Execute(AbstractLibraryInstance instance, CommandInput input);
}
class CmdTestNetwork : Command
{
public override string[] Aliases => new string[] { "test-network" };
public override void Execute(AbstractLibraryInstance instance, CommandInput input)
{
Program.Network.TestConnection();
}
}
class CmdNetworkDiscovery : Command
{
public override string[] Aliases => new string[] { "network-discovery" };
public override void Execute(AbstractLibraryInstance instance, CommandInput input)
{
Postman.SendToChannel(Channels.Discovery, new DiscoveryMessage()).ExpectMultiple().Timeout(5_000)
.Then(msgs=>{
foreach(var msg in msgs)
{
ConsoleP.AppendLine("Node: ");
}
return true;
}).Send();
}
}
class CommandInput
{
public string Id { get; private set; }
public Dictionary<string, string> Parameters { get; private set; } = new Dictionary<string, string>();
public List<string> Arguments { get; private set; } = new List<string>();
private CommandInput()
{
}
/**
* dmx -q=10
*/
public static CommandInput ParseLine(string line)
{
var input = new CommandInput()
{
Id = ""
};
line = line.Trim();
int i = 0;
int max = line.Length;
while (i < max && !line[i].Equals(' '))
{
input.Id += line[i];
i++;
}
if (input.Id.Length == 0)
throw new Exception();
/**
* 0 - searching for next
* 1 - parameter name read
* 2 - parameter value read
* 3 - parameter string value read
* 4 - argument read
* 5 - argument string read
*/
int mode = 0;
string name="", value="";
i++;
while (i < max)
{
if (line[i].Equals(' '))
{
if (mode == 0) continue;
if (mode == 1) { input.Parameters.Add(name, null); name = ""; mode = 0; continue; }
if (mode == 2) { input.Parameters.Add(name, value); name = ""; value = ""; mode = 0; continue; }
if (mode == 4) { input.Arguments.Add(value); value = ""; mode = 0; continue; }
}
else if (mode==0 && line[i].Equals('-'))
{
mode = 1; continue;
}
else if (mode == 1 && line[i].Equals('='))
{
mode = 2; continue;
}
else if ((mode == 2 || mode == 4) && line[i].Equals('"'))
{
mode++; continue;
}
else if (line[i].Equals('"') && value.Length>0 && !value[value.Length-1].Equals('\\'))
{
if (mode == 3) { input.Parameters.Add(name, value); name = ""; value = ""; mode = 0; continue; }
if (mode == 5) { input.Arguments.Add(value); value = ""; mode = 0; continue; }
}
if(mode==0) { mode = 4; }
else if(mode==1) { name += line[i]; }
else { value += line[i]; }
i++;
}
if (value.Length > 0)
if (mode > 4)
input.Arguments.Add(value);
else
input.Parameters.Add(name, value);
return input;
}
}
}
using Newtonsoft.Json;
using RabbitMQ.Client;
using System;
using System.Collections.Generic;
using System.Text;
namespace KazetaNode.Coms
{
enum Channels
{
Discovery,Capture,Deliver,Process, Persist
}
class Postman
{
public delegate bool ThenAction(List<IMessage> messages);
public delegate bool TimeoutAction();
public long TimeoutMax { get; private set; }
public long TimeStart { get; set; } = -1;
public TimeoutAction TimeoutAc { get; private set; }
public ThenAction ThenAc { get; private set; } = null;
public bool Multiple { get; private set; } = false;
public string Exchange { get; private set; }
public string Route { get; private set; }
public IMessage Message { get; private set; }
protected internal List<IMessage> Responses = new List<IMessage>();
public static Postman SendToNode(string node,IMessage message)
{
return new Postman
{
Exchange = "",
Route = node,
Message = message
};
}
public static Postman SendToChannel(Channels channel,IMessage message)
{
string node = "";
switch(channel)
{
case Channels.Discovery: node = Network.ROUTING_DISCOVERY; break;
case Channels.Capture: node = "kazeta.capture"; break;
case Channels.Deliver: node = "kazeta.deliver"; break;
case Channels.Persist: node = "kazeta.persist"; break;
case Channels.Process: node = "kazeta.process"; break;
}
return new Postman
{
Exchange = Network.EXCHANGE,
Route = node,
Message = message
};
}
public Postman Timeout(long miliseconds,TimeoutAction action=null)
{
if (TimeStart != -1)
throw new Exception("Already started");
this.TimeoutAc = action;
this.TimeoutMax = miliseconds;
return this;
}
public Postman Then(ThenAction action)
{
if (TimeStart != -1)
throw new Exception("Already started");
this.ThenAc = action;
return this;
}
public Postman ExpectSingle()
{
if (TimeStart != -1)
throw new Exception("Already started");
this.Multiple = false;
return this;
}
public Postman ExpectMultiple()
{
if (TimeStart != -1)
throw new Exception("Already started");
this.Multiple = true;
return this;
}
public void Send()
{
if (TimeStart != -1)
throw new Exception("Already started");
Program.Network.SendPostMan(this);
}
}
}
using KazetaNode.Modules.Capture.Messages;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Text;
namespace KazetaNode.Coms
{
abstract class IMessage
{
[JsonProperty("message_id")]
public string MessageId { get; set; } = Guid.NewGuid().ToString();
[JsonProperty("response_id")]
public string ResponseId { get; set; }
[JsonProperty("sender")]
public string Sender { get; set; }
[JsonProperty("message_type")]
public abstract string MessageType { get; }
}
class TestMessage : IMessage
{
public override string MessageType => this.GetType().FullName;
}
class DiscoveryMessage : IMessage
{
public override string MessageType => this.GetType().FullName;
}
class DiscoveryReplyMessage : IMessage
{
public override string MessageType => this.GetType().FullName;
}
}
using KazetaNode.Helpers;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Threading;
namespace KazetaNode.Coms
{
class Network
{
public delegate void ReceiveMessage(IMessage message);
string id;
IConnection con;
public IModel channel;
ConnectionFactory factory;
List<Postman> Postmans = new List<Postman>();
Dictionary<Type, List<ReceiveMessage>> Handlers=new Dictionary<Type, List<Network.ReceiveMessage>>();
Thread TimeoutThread;
Stopwatch watch;
int timeout;
public Network(dynamic config)
{
id = config["id"];
QUEUE = QUEUE_PREFIX + id;
factory = new ConnectionFactory
{
UserName = config["network"]["user"],
Password = config["network"]["password"],
VirtualHost = config["network"]["virtual_host"],
HostName = config["network"]["hostname"],
Port = Int32.Parse(config["network"]["port"])
};
timeout = Int32.Parse(config["experimentional"]["net_timeout"]);
watch = new Stopwatch();
TimeoutThread = new Thread(new ThreadStart(delegate
{
while(true)
{
Thread.Sleep(timeout);
for (int i = Postmans.Count - 1; i >= 0; i--)
{
Postman p = Postmans[i];
if (watch.ElapsedMilliseconds>p.TimeoutMax+p.TimeStart)
{
if (p.Responses.Count > 0)
p.ThenAc?.Invoke(p.Responses);
else p.TimeoutAc?.Invoke();
Postmans.Remove(p);
}
}
}
}));
}
public static readonly string EXCHANGE = "kazeta.network";
public static readonly string ROUTING_DISCOVERY = "kazeta.route.discovery";
public static readonly string QUEUE_PREFIX = "app.kazeta.node.";
private readonly string QUEUE;
public static void DiscoveryReply(IMessage msg)
{
Program.Network.channel.BasicPublish("", QUEUE_PREFIX+msg.Sender, null, Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new DiscoveryReplyMessage() { ResponseId = msg.MessageId })));
}
public void Connect()
{
TimeoutThread.Start();
watch.Start();
con = factory.CreateConnection();
channel = con.CreateModel();
channel.ExchangeDeclare(EXCHANGE, ExchangeType.Topic, true, false);
channel.QueueDeclare(QUEUE, true,true,false);
channel.QueueBind(queue: QUEUE, exchange: EXCHANGE, routingKey: ROUTING_DISCOVERY);
RegisterHandler(typeof(DiscoveryMessage), DiscoveryReply);
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var json = Encoding.UTF8.GetString(ea.Body);
JObject dyn = JsonConvert.DeserializeObject<JObject>(json);
var st = dyn.GetValue("message_type").ToString();
Type type = typeof(IMessage).Assembly.GetType(st);
IMessage msg = (IMessage)JsonConvert.DeserializeObject(json,type);
for (int i = Postmans.Count - 1; i >= 0; i--)
{
Postman p = Postmans[i];
if (p.Message.MessageId.Equals(msg.ResponseId))
{
p.Responses.Add(msg);
if (!p.Multiple)
{
Postmans.Remove(p);
p.ThenAc?.Invoke(p.Responses);
}
return;
}
}
if(Handlers.ContainsKey(msg.GetType()))
{
foreach (ReceiveMessage recv in Handlers[msg.GetType()])
recv.Invoke(msg);
}
};
channel.BasicConsume(queue: "app.kazeta.node." + id,
autoAck: true,
consumer: consumer);
}
internal void SendPostMan(Postman postman)
{
postman.TimeStart = watch.ElapsedMilliseconds;
Postmans.Add(postman);
postman.Message.Sender = Program.NodeId;
Program.Network.channel.BasicPublish(postman.Exchange, postman.Route, null, Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(postman.Message)));
}
public void RegisterHandler(Type message, ReceiveMessage handler)
{
if (!Handlers.ContainsKey(message))
Handlers.Add(message, new List<ReceiveMessage>());
Handlers[message].Add(handler);
}
public void TestConnection()
{
var test = new TestMessage();
test.ResponseId = test.MessageId;
Postman.SendToNode("app.kazeta.node." + id, test).ExpectSingle().Timeout(9000).Then(a => {
ConsoleP.AppendLine("Network: Test complete (send: ok, recv: ok)");
return true;
}).Send();
}
public void Close()
{
channel.Close();
con.Close();
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
namespace KazetaNode
{
class ConsoleP
{
private static string LinePrefix="";
private static string Line = "";
private static IEnumerable<string> Autocomplete;
public static void SetAutoComplete(IEnumerable<string> autocomplete)
{
ConsoleP.Autocomplete = autocomplete;
}
public static void ShowInterface()
{
ClearLine();
LinePrefix = "kazeta@" + Program.NodeId + ": ";
Console.Write(LinePrefix);
}
public static string ReadLine()
{
while (true)
{
var key = Console.ReadKey();
if (key.Key == ConsoleKey.LeftArrow)
{
Console.SetCursorPosition(Console.CursorLeft>LinePrefix.Length? Console.CursorLeft-1: Console.CursorLeft, Console.CursorTop);
}
else if (key.Key==ConsoleKey.Enter)
{
Console.WriteLine(LinePrefix + Line);
string Data = Line;
LinePrefix = "kazeta@" + Program.NodeId + ": ";
Console.Write(LinePrefix);
Line = "";
return Data;
}
else if (key.Key == ConsoleKey.Tab)
{
if (Line.Length == 0)
{
ClearLine();
Console.WriteLine(String.Join(", ",Autocomplete));
Console.Write(LinePrefix + Line);
}
else {
var res=Autocomplete.Where(e => e.StartsWith(Line));
if (res.Count() == 1) {
Line += res.First().Substring(Line.Length);
ClearLine();
Console.Write(LinePrefix + Line);
}
else
{
ClearLine();
Console.WriteLine(String.Join(", ", res));
Console.Write(LinePrefix + Line);
}
}
}
else
Line += key.KeyChar;
}
}
public static void ClearLine(int pos=0)
{
Console.SetCursorPosition(0, Console.CursorTop-pos);
Console.Write(new string(' ', Console.BufferWidth));
Console.SetCursorPosition(0, Console.CursorTop-pos-1);
}
public static void AppendLine(string line)
{
ClearLine();
Console.WriteLine(line);
Console.Write(LinePrefix+Line);
}
public static void WriteLine(string line)
{
Console.WriteLine(line);
}
public static void Write(string text)
{
Console.Write(text);
}
}
}
using KazetaNode.Modules.Persist.Entities;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Text;
namespace KazetaNode
{
class DatabaseContext : DbContext
{
public DbSet<SftpUser> SftpUsers { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite("Data Source=data.db");
}
}
}
using KazetaNode.Helpers;
using KazetaNode.Models;
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
namespace KazetaNode
{
class Ffmpeg
{
}
}
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace KazetaNode.Helpers
{
class FileSystemHelper
{
public static long DirSize(DirectoryInfo d)
{
long size = 0;
FileInfo[] fis = d.GetFiles();
foreach (FileInfo fi in fis)
{
size += fi.Length;
}
DirectoryInfo[] dis = d.GetDirectories();
foreach (DirectoryInfo di in dis)
{
size += DirSize(di);
}
return size;
}
public static string GetProjectFolder(string location,ProjectIdDescriptor id)
{
return Path.Combine(location, id.Room, id.Year, id.Month,id.Day+"_"+id.Hour+"_"+id.Random);
}
public static void CreateProjectFolder(string location,ProjectIdDescriptor id)
{
var path = GetProjectFolder(location, id);
Directory.CreateDirectory(path);
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace KazetaNode.Helpers
{
class InteractiveWorkBuilder
{
public void Start()
{
Console.BackgroundColor = ConsoleColor.Black;
Console.ForegroundColor = ConsoleColor.Red;
Console.Clear();
Console.WriteLine("========================================");
Console.WriteLine(" Work builder ");
Console.WriteLine("========================================");
Console.WriteLine("Event name [cs]: ");
Console.WriteLine("Event name [en]: ");
Console.WriteLine("Event tags: ");
Console.WriteLine("Author: ");
Console.WriteLine("Speakers usernames or fullnames delimetered with ',': ");
Console.WriteLine("Live stream (y/n): ");
Console.WriteLine("Capture configuration");
Console.WriteLine("----------------------------------------");
Console.WriteLine("Select room: ");
Console.WriteLine("Capture start date: ");
Console.WriteLine("Capture end date: ");
Console.WriteLine("Select capture mode: ");
Console.WriteLine("1) Speaker with presentation and blackboard (default)");
Console.WriteLine("2) Speaker with blackboard");
Console.WriteLine("3) Speaker with presentation");
Console.WriteLine("4) Speaker");
Console.WriteLine("5) Blackboard");
Console.WriteLine("6) Audio only");
Console.WriteLine("7) Speaker+audiance with presentation and blackboard (GDPR WARNING)");
Console.WriteLine("Video quality (4k,fullhd,hd,480p): ");
Console.WriteLine("Process configuration");
Console.WriteLine("----------------------------------------");
Console.WriteLine("Delivery configuration");
Console.WriteLine("----------------------------------------");
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace KazetaNode.Helpers
{
class DirectMessageAttribute : Attribute
{
}
class TopicMessageAttribute : Attribute
{
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace KazetaNode.Helpers
{
class ProjectIdGenerator
{
public static string Generate(string room,int year,int month,int day,int hour_start,string random)
{
return String.Join("_", room, year, month, day, hour_start, random);
}
}
class ProjectIdDescriptor
{
private string Id;
public ProjectIdDescriptor(string id)
{
this.Id = id;
}
public string Room { get => Id.Split("_")[0]; }
public string Year { get => Id.Split("_")[1]; }
public string Month { get => Id.Split("_")[2]; }
public string Day { get => Id.Split("_")[3]; }
public string Hour { get => Id.Split("_")[4]; }
public string Random { get => Id.Split("_")[5]; }
}
}
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
namespace KazetaNode.Helpers
{
class Shell
{
public static ShellResult Execute(string filename,string arguments,int? miliseconds = null)
{
Process process = new Process()
{
StartInfo = new ProcessStartInfo
{
FileName = filename,
Arguments = arguments,
RedirectStandardInput = true,
RedirectStandardError = true,
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
}
};
process.Start();
if (miliseconds == null)
process.WaitForExit();
else
process.WaitForExit((int)miliseconds);
return new ShellResult()
{
Output = process.StandardOutput,
Error = process.StandardError,
ExitCode=process.ExitCode
};
}
}
class ShellResult
{