mirror of
https://github.com/azaion/annotations.git
synced 2026-04-22 09:36:30 +00:00
move zmq port to config file for C# and python
This commit is contained in:
@@ -8,7 +8,7 @@ namespace Azaion.Common.DTO.Config;
|
|||||||
|
|
||||||
public class AppConfig
|
public class AppConfig
|
||||||
{
|
{
|
||||||
public ApiConfig ApiConfig { get; set; } = null!;
|
public PythonConfig PythonConfig { get; set; } = null!;
|
||||||
|
|
||||||
public QueueConfig QueueConfig { get; set; } = null!;
|
public QueueConfig QueueConfig { get; set; } = null!;
|
||||||
|
|
||||||
|
|||||||
@@ -2,13 +2,12 @@
|
|||||||
using Azaion.Common.Database;
|
using Azaion.Common.Database;
|
||||||
using Azaion.Common.DTO.Config;
|
using Azaion.Common.DTO.Config;
|
||||||
using Azaion.CommonSecurity;
|
using Azaion.CommonSecurity;
|
||||||
|
using Azaion.CommonSecurity.DTO;
|
||||||
using Azaion.CommonSecurity.DTO.Commands;
|
using Azaion.CommonSecurity.DTO.Commands;
|
||||||
using MessagePack;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using NetMQ;
|
using NetMQ;
|
||||||
using NetMQ.Sockets;
|
using NetMQ.Sockets;
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace Azaion.Common.Services;
|
namespace Azaion.Common.Services;
|
||||||
|
|
||||||
@@ -17,16 +16,18 @@ public interface IInferenceService
|
|||||||
Task RunInference(List<string> mediaPaths, Func<AnnotationImage, Task> processAnnotation, CancellationToken ct = default);
|
Task RunInference(List<string> mediaPaths, Func<AnnotationImage, Task> processAnnotation, CancellationToken ct = default);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PythonInferenceService(ILogger<PythonInferenceService> logger, IOptions<AIRecognitionConfig> aiConfigOptions) : IInferenceService
|
public class PythonInferenceService(ILogger<PythonInferenceService> logger, IOptions<PythonConfig> pythonConfigOptions, IOptions<AIRecognitionConfig> aiConfigOptions) : IInferenceService
|
||||||
{
|
{
|
||||||
public async Task RunInference(List<string> mediaPaths, Func<AnnotationImage, Task> processAnnotation, CancellationToken ct = default)
|
public async Task RunInference(List<string> mediaPaths, Func<AnnotationImage, Task> processAnnotation, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
|
var pythonConfig = pythonConfigOptions.Value;
|
||||||
|
var aiConfig = aiConfigOptions.Value;
|
||||||
|
|
||||||
using var dealer = new DealerSocket();
|
using var dealer = new DealerSocket();
|
||||||
var clientId = Guid.NewGuid();
|
var clientId = Guid.NewGuid();
|
||||||
dealer.Options.Identity = Encoding.UTF8.GetBytes(clientId.ToString("N"));
|
dealer.Options.Identity = Encoding.UTF8.GetBytes(clientId.ToString("N"));
|
||||||
dealer.Connect($"tcp://{SecurityConstants.ZMQ_HOST}:{SecurityConstants.ZMQ_PORT}");
|
dealer.Connect($"tcp://{pythonConfig.ZeroMqHost}:{pythonConfig.ZeroMqPort}");
|
||||||
|
|
||||||
var aiConfig = aiConfigOptions.Value;
|
|
||||||
aiConfig.Paths = mediaPaths;
|
aiConfig.Paths = mediaPaths;
|
||||||
dealer.SendFrame(RemoteCommand.Serialize(CommandType.Inference, aiConfig));
|
dealer.SendFrame(RemoteCommand.Serialize(CommandType.Inference, aiConfig));
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
namespace Azaion.CommonSecurity.DTO;
|
|
||||||
|
|
||||||
public class ApiConfig
|
|
||||||
{
|
|
||||||
public string Url { get; set; } = null!;
|
|
||||||
public int RetryCount {get;set;}
|
|
||||||
public double TimeoutSeconds { get; set; }
|
|
||||||
public string ResourcesFolder { get; set; } = "";
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
namespace Azaion.CommonSecurity.DTO;
|
||||||
|
|
||||||
|
public class PythonConfig
|
||||||
|
{
|
||||||
|
public string ZeroMqHost { get; set; }
|
||||||
|
public int ZeroMqPort { get; set; }
|
||||||
|
public double OneTryTimeoutSeconds { get; set; }
|
||||||
|
public int RetryCount {get;set;}
|
||||||
|
|
||||||
|
public string ResourcesFolder { get; set; } = "";
|
||||||
|
}
|
||||||
@@ -2,5 +2,5 @@
|
|||||||
|
|
||||||
public class SecureAppConfig
|
public class SecureAppConfig
|
||||||
{
|
{
|
||||||
public ApiConfig ApiConfig { get; set; } = null!;
|
public PythonConfig PythonConfig { get; set; } = null!;
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
using System.Security.Claims;
|
|
||||||
using MessagePack;
|
using MessagePack;
|
||||||
|
|
||||||
namespace Azaion.CommonSecurity.DTO;
|
namespace Azaion.CommonSecurity.DTO;
|
||||||
@@ -9,18 +8,4 @@ public class User
|
|||||||
[Key("i")] public string Id { get; set; } = "";
|
[Key("i")] public string Id { get; set; } = "";
|
||||||
[Key("e")] public string Email { get; set; } = "";
|
[Key("e")] public string Email { get; set; } = "";
|
||||||
[Key("r")]public RoleEnum Role { get; set; }
|
[Key("r")]public RoleEnum Role { get; set; }
|
||||||
|
|
||||||
//For deserializing
|
|
||||||
public User(){}
|
|
||||||
|
|
||||||
public User(IEnumerable<Claim> claims)
|
|
||||||
{
|
|
||||||
var claimDict = claims.ToDictionary(x => x.Type, x => x.Value);
|
|
||||||
|
|
||||||
Id = claimDict[SecurityConstants.CLAIM_NAME_ID];
|
|
||||||
Email = claimDict[SecurityConstants.CLAIM_EMAIL];
|
|
||||||
if (!Enum.TryParse(claimDict[SecurityConstants.CLAIM_ROLE], out RoleEnum role))
|
|
||||||
role = RoleEnum.None;
|
|
||||||
Role = role;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -6,23 +6,13 @@ public class SecurityConstants
|
|||||||
|
|
||||||
public const string DUMMY_DIR = "dummy";
|
public const string DUMMY_DIR = "dummy";
|
||||||
|
|
||||||
#region ApiConfig
|
#region PythonConfig
|
||||||
|
|
||||||
public const string DEFAULT_API_URL = "https://api.azaion.com/";
|
|
||||||
public const int DEFAULT_API_RETRY_COUNT = 3;
|
|
||||||
public const int DEFAULT_API_TIMEOUT_SECONDS = 40;
|
|
||||||
|
|
||||||
public const string CLAIM_NAME_ID = "nameid";
|
|
||||||
public const string CLAIM_EMAIL = "unique_name";
|
|
||||||
public const string CLAIM_ROLE = "role";
|
|
||||||
|
|
||||||
#endregion ApiConfig
|
|
||||||
|
|
||||||
#region SocketClient
|
|
||||||
public const string ZMQ_HOST = "127.0.0.1";
|
|
||||||
public const int ZMQ_PORT = 5127;
|
|
||||||
|
|
||||||
#endregion SocketClient
|
|
||||||
|
|
||||||
public const string AZAION_INFERENCE_PATH = "azaion-inference.exe";
|
public const string AZAION_INFERENCE_PATH = "azaion-inference.exe";
|
||||||
|
|
||||||
|
public const string DEFAULT_ZMQ_HOST = "127.0.0.1";
|
||||||
|
public const int DEFAULT_ZMQ_PORT = 5127;
|
||||||
|
public const int DEFAULT_RETRY_COUNT = 25;
|
||||||
|
public const int DEFAULT_TIMEOUT_SECONDS = 5;
|
||||||
|
|
||||||
|
#endregion PythonConfig
|
||||||
}
|
}
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
using System.IdentityModel.Tokens.Jwt;
|
|
||||||
using System.Net;
|
|
||||||
using System.Net.Http.Headers;
|
|
||||||
using System.Security;
|
|
||||||
using System.Text;
|
|
||||||
using Azaion.CommonSecurity.DTO;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace Azaion.CommonSecurity.Services;
|
|
||||||
|
|
||||||
public class AzaionApiClient(HttpClient httpClient) : IDisposable
|
|
||||||
{
|
|
||||||
const string JSON_MEDIA = "application/json";
|
|
||||||
|
|
||||||
private static ApiConfig _apiConfig = null!;
|
|
||||||
|
|
||||||
private string Email { get; set; } = null!;
|
|
||||||
private SecureString Password { get; set; } = new();
|
|
||||||
private string JwtToken { get; set; } = null!;
|
|
||||||
public User User { get; set; } = null!;
|
|
||||||
|
|
||||||
public static AzaionApiClient Create(ApiCredentials credentials, ApiConfig apiConfig)
|
|
||||||
{
|
|
||||||
_apiConfig = apiConfig;
|
|
||||||
var api = new AzaionApiClient(new HttpClient
|
|
||||||
{
|
|
||||||
BaseAddress = new Uri(_apiConfig.Url),
|
|
||||||
Timeout = TimeSpan.FromSeconds(_apiConfig.TimeoutSeconds)
|
|
||||||
});
|
|
||||||
|
|
||||||
api.EnterCredentials(credentials);
|
|
||||||
return api;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void EnterCredentials(ApiCredentials credentials)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(credentials.Email) || string.IsNullOrWhiteSpace(credentials.Password))
|
|
||||||
throw new Exception("Email or password is empty!");
|
|
||||||
|
|
||||||
Email = credentials.Email;
|
|
||||||
Password = credentials.Password.ToSecureString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Stream> GetResource(string fileName, string password, HardwareInfo hardware, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
var response = await Send(httpClient, new HttpRequestMessage(HttpMethod.Post, $"/resources/get/{_apiConfig.ResourcesFolder}")
|
|
||||||
{
|
|
||||||
Content = new StringContent(JsonConvert.SerializeObject(new { fileName, password, hardware }), Encoding.UTF8, JSON_MEDIA)
|
|
||||||
}, cancellationToken);
|
|
||||||
return await response.Content.ReadAsStreamAsync(cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task Authorize()
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(Email) || Password.Length == 0)
|
|
||||||
throw new Exception("Email or password is empty! Please do EnterCredentials first!");
|
|
||||||
|
|
||||||
var payload = new
|
|
||||||
{
|
|
||||||
email = Email,
|
|
||||||
password = Password.ToRealString()
|
|
||||||
};
|
|
||||||
var response = await httpClient.PostAsync(
|
|
||||||
"login",
|
|
||||||
new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, JSON_MEDIA));
|
|
||||||
|
|
||||||
if (!response.IsSuccessStatusCode)
|
|
||||||
throw new Exception($"EnterCredentials failed: {response.StatusCode}");
|
|
||||||
|
|
||||||
var responseData = await response.Content.ReadAsStringAsync();
|
|
||||||
|
|
||||||
var result = JsonConvert.DeserializeObject<LoginResponse>(responseData);
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(result?.Token))
|
|
||||||
throw new Exception("JWT Token not found in response");
|
|
||||||
|
|
||||||
var handler = new JwtSecurityTokenHandler();
|
|
||||||
var token = handler.ReadJwtToken(result.Token);
|
|
||||||
|
|
||||||
User = new User(token.Claims);
|
|
||||||
JwtToken = result.Token;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<HttpResponseMessage> Send(HttpClient client, HttpRequestMessage request, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(JwtToken))
|
|
||||||
await Authorize();
|
|
||||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", JwtToken);
|
|
||||||
var response = await client.SendAsync(request, cancellationToken);
|
|
||||||
|
|
||||||
if (response.StatusCode == HttpStatusCode.Unauthorized)
|
|
||||||
{
|
|
||||||
await Authorize();
|
|
||||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", JwtToken);
|
|
||||||
response = await client.SendAsync(request, cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response.IsSuccessStatusCode)
|
|
||||||
return response;
|
|
||||||
|
|
||||||
var result = await response.Content.ReadAsStringAsync(cancellationToken);
|
|
||||||
throw new Exception($"Failed: {response.StatusCode}! Result: {result}");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
httpClient.Dispose();
|
|
||||||
Password.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -19,7 +19,6 @@ public interface IAuthProvider
|
|||||||
User CurrentUser { get; }
|
User CurrentUser { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public class PythonResourceLoader : IResourceLoader, IAuthProvider
|
public class PythonResourceLoader : IResourceLoader, IAuthProvider
|
||||||
{
|
{
|
||||||
private readonly DealerSocket _dealer = new();
|
private readonly DealerSocket _dealer = new();
|
||||||
@@ -27,11 +26,11 @@ public class PythonResourceLoader : IResourceLoader, IAuthProvider
|
|||||||
|
|
||||||
public User CurrentUser { get; set; } = null!;
|
public User CurrentUser { get; set; } = null!;
|
||||||
|
|
||||||
public PythonResourceLoader()
|
public PythonResourceLoader(PythonConfig config)
|
||||||
{
|
{
|
||||||
StartPython();
|
//StartPython();
|
||||||
_dealer.Options.Identity = Encoding.UTF8.GetBytes(_clientId.ToString("N"));
|
_dealer.Options.Identity = Encoding.UTF8.GetBytes(_clientId.ToString("N"));
|
||||||
_dealer.Connect($"tcp://{SecurityConstants.ZMQ_HOST}:{SecurityConstants.ZMQ_PORT}");
|
_dealer.Connect($"tcp://{config.ZeroMqHost}:{config.ZeroMqPort}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StartPython()
|
private void StartPython()
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from user cimport User
|
from user cimport User
|
||||||
from credentials cimport Credentials
|
from credentials cimport Credentials
|
||||||
from file_data cimport FileData
|
|
||||||
|
|
||||||
cdef class ApiClient:
|
cdef class ApiClient:
|
||||||
cdef public Credentials credentials
|
cdef public Credentials credentials
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
pyinstaller --onefile ^
|
||||||
|
--collect-all pyyaml ^
|
||||||
|
--collect-all jwt ^
|
||||||
|
--collect-all requests ^
|
||||||
|
--collect-all psutil ^
|
||||||
|
--collect-all msgpack ^
|
||||||
|
--collect-all zmq ^
|
||||||
|
--collect-all cryptography ^
|
||||||
|
--collect-all cv2 ^
|
||||||
|
--collect-all onnxruntime ^
|
||||||
|
--hidden-import constants ^
|
||||||
|
--hidden-import annotation ^
|
||||||
|
--hidden-import credentials ^
|
||||||
|
--hidden-import file_data ^
|
||||||
|
--hidden-import user ^
|
||||||
|
--hidden-import security ^
|
||||||
|
--hidden-import secure_model ^
|
||||||
|
--hidden-import api_client ^
|
||||||
|
--hidden-import hardware_service ^
|
||||||
|
--hidden-import remote_command ^
|
||||||
|
--hidden-import ai_config ^
|
||||||
|
--hidden-import inference ^
|
||||||
|
--hidden-import remote_command_handler ^
|
||||||
|
start.py
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
zmq_port: 5128
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
cdef int ZMQ_PORT = 5127 # Port for the zmq
|
cdef str CONFIG_FILE # Port for the zmq
|
||||||
|
|
||||||
cdef int QUEUE_MAXSIZE # Maximum size of the command queue
|
cdef int QUEUE_MAXSIZE # Maximum size of the command queue
|
||||||
cdef str COMMANDS_QUEUE # Name of the commands queue in rabbit
|
cdef str COMMANDS_QUEUE # Name of the commands queue in rabbit
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
cdef int ZMQ_PORT = 5127 # Port for the zmq
|
cdef str CONFIG_FILE = "config.yaml" # Port for the zmq
|
||||||
|
|
||||||
cdef int QUEUE_MAXSIZE = 1000 # Maximum size of the command queue
|
cdef int QUEUE_MAXSIZE = 1000 # Maximum size of the command queue
|
||||||
cdef str COMMANDS_QUEUE = "azaion-commands"
|
cdef str COMMANDS_QUEUE = "azaion-commands"
|
||||||
cdef str ANNOTATIONS_QUEUE = "azaion-annotations"
|
cdef str ANNOTATIONS_QUEUE = "azaion-annotations"
|
||||||
|
|
||||||
@@ -9,4 +9,4 @@ cdef str QUEUE_CONFIG_FILENAME = "secured-config.json"
|
|||||||
cdef str AI_MODEL_FILE = "azaion.onnx"
|
cdef str AI_MODEL_FILE = "azaion.onnx"
|
||||||
|
|
||||||
cdef bytes DONE_SIGNAL = b"DONE"
|
cdef bytes DONE_SIGNAL = b"DONE"
|
||||||
cdef int MODEL_BATCH_SIZE = 4
|
cdef int MODEL_BATCH_SIZE = 4
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import zmq
|
|||||||
from threading import Thread, Event
|
from threading import Thread, Event
|
||||||
from remote_command cimport RemoteCommand
|
from remote_command cimport RemoteCommand
|
||||||
cimport constants
|
cimport constants
|
||||||
|
import yaml
|
||||||
|
|
||||||
cdef class RemoteCommandHandler:
|
cdef class RemoteCommandHandler:
|
||||||
def __init__(self, object on_command):
|
def __init__(self, object on_command):
|
||||||
@@ -12,7 +12,9 @@ cdef class RemoteCommandHandler:
|
|||||||
|
|
||||||
self._router = self._context.socket(zmq.ROUTER)
|
self._router = self._context.socket(zmq.ROUTER)
|
||||||
self._router.setsockopt(zmq.LINGER, 0)
|
self._router.setsockopt(zmq.LINGER, 0)
|
||||||
self._router.bind(f'tcp://*:{constants.ZMQ_PORT}')
|
with open(<str>constants.CONFIG_FILE, "r") as f:
|
||||||
|
config = yaml.safe_load(f)
|
||||||
|
self._router.bind(f'tcp://*:{config["zmq_port"]}')
|
||||||
|
|
||||||
self._dealer = self._context.socket(zmq.DEALER)
|
self._dealer = self._context.socket(zmq.DEALER)
|
||||||
self._dealer.setsockopt(zmq.LINGER, 0)
|
self._dealer.setsockopt(zmq.LINGER, 0)
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ public partial class App
|
|||||||
private IMediator _mediator = null!;
|
private IMediator _mediator = null!;
|
||||||
private FormState _formState = null!;
|
private FormState _formState = null!;
|
||||||
|
|
||||||
private readonly PythonResourceLoader _resourceLoader = new();
|
private PythonResourceLoader _resourceLoader = null!;
|
||||||
private Stream _securedConfig = null!;
|
private Stream _securedConfig = null!;
|
||||||
|
|
||||||
private void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
|
private void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
|
||||||
@@ -54,23 +54,25 @@ public partial class App
|
|||||||
"Azaion.Dataset"
|
"Azaion.Dataset"
|
||||||
];
|
];
|
||||||
|
|
||||||
private static ApiConfig ReadConfig()
|
private static PythonConfig ReadPythonConfig()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!File.Exists(SecurityConstants.CONFIG_PATH))
|
if (!File.Exists(SecurityConstants.CONFIG_PATH))
|
||||||
throw new FileNotFoundException(SecurityConstants.CONFIG_PATH);
|
throw new FileNotFoundException(SecurityConstants.CONFIG_PATH);
|
||||||
var configStr = File.ReadAllText(SecurityConstants.CONFIG_PATH);
|
var configStr = File.ReadAllText(SecurityConstants.CONFIG_PATH);
|
||||||
return JsonConvert.DeserializeObject<SecureAppConfig>(configStr)!.ApiConfig;
|
return JsonConvert.DeserializeObject<SecureAppConfig>(configStr)!.PythonConfig;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Console.WriteLine(e);
|
Console.WriteLine(e);
|
||||||
return new ApiConfig
|
return new PythonConfig
|
||||||
{
|
{
|
||||||
Url = SecurityConstants.DEFAULT_API_URL,
|
ZeroMqHost = SecurityConstants.DEFAULT_ZMQ_HOST,
|
||||||
RetryCount = SecurityConstants.DEFAULT_API_RETRY_COUNT,
|
ZeroMqPort = SecurityConstants.DEFAULT_ZMQ_PORT,
|
||||||
TimeoutSeconds = SecurityConstants.DEFAULT_API_TIMEOUT_SECONDS,
|
OneTryTimeoutSeconds = SecurityConstants.DEFAULT_TIMEOUT_SECONDS,
|
||||||
|
RetryCount = SecurityConstants.DEFAULT_RETRY_COUNT,
|
||||||
|
|
||||||
ResourcesFolder = ""
|
ResourcesFolder = ""
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -80,9 +82,10 @@ public partial class App
|
|||||||
{
|
{
|
||||||
new ConfigUpdater().CheckConfig();
|
new ConfigUpdater().CheckConfig();
|
||||||
var login = new Login();
|
var login = new Login();
|
||||||
|
var config = ReadPythonConfig();
|
||||||
|
_resourceLoader = new PythonResourceLoader(config);
|
||||||
login.CredentialsEntered += (_, credentials) =>
|
login.CredentialsEntered += (_, credentials) =>
|
||||||
{
|
{
|
||||||
var config = ReadConfig();
|
|
||||||
credentials.Folder = config.ResourcesFolder;
|
credentials.Folder = config.ResourcesFolder;
|
||||||
_resourceLoader.Login(credentials);
|
_resourceLoader.Login(credentials);
|
||||||
_securedConfig = _resourceLoader.LoadFileFromPython("secured-config.json");
|
_securedConfig = _resourceLoader.LoadFileFromPython("secured-config.json");
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
{
|
{
|
||||||
"ApiConfig": {
|
"PythonConfig": {
|
||||||
"TimeoutSeconds": 20.0
|
"ZeroMqHost": "127.0.0.1",
|
||||||
|
"ZeroMqPort": 5128,
|
||||||
|
"RetryCount": 25,
|
||||||
|
"TimeoutSeconds": 5
|
||||||
},
|
},
|
||||||
"DirectoriesConfig": {
|
"DirectoriesConfig": {
|
||||||
"VideosDirectory": "E:\\Azaion6",
|
"VideosDirectory": "E:\\Azaion6",
|
||||||
|
|||||||
Reference in New Issue
Block a user