Compare commits
4
Commits
73ae729e35
...
6c105ac757
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c105ac757 | ||
|
|
beb0134dfc | ||
|
|
fc7eeb1d57 | ||
|
|
2fc5ae42a3 |
@@ -5,7 +5,7 @@ use std::io::{BufRead, BufReader};
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use lumiere_domain::video::error::VideoError;
|
use lumiere_domain::video::error::VideoError;
|
||||||
use lumiere_domain::video::model::library_item::{LibraryItem, ReadLibraryItem};
|
use lumiere_domain::video::model::library_item::{LibraryItem, LibraryRawItem};
|
||||||
use lumiere_domain::video::port::VideoPort;
|
use lumiere_domain::video::port::VideoPort;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -18,12 +18,12 @@ impl VideoService {
|
|||||||
Self { video_port }
|
Self { video_port }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list_root_folder(self) -> Result<Vec<LibraryItem>, VideoError> {
|
pub fn list_root_folder(&self) -> Result<Vec<LibraryItem>, VideoError> {
|
||||||
let read_items_with_possibly_no_id = self.video_port.list_root_folder()?;
|
let read_items_with_possibly_no_id = self.video_port.list_root_folder()?;
|
||||||
let items_with_id = read_items_with_possibly_no_id.iter()
|
let items_with_id = read_items_with_possibly_no_id.iter()
|
||||||
.map(ReadLibraryItem::map_to_library_item)
|
.map(LibraryRawItem::map_to_library_item)
|
||||||
.collect();
|
.collect();
|
||||||
self.video_port.save_all(items_with_id);
|
self.video_port.save_all(&items_with_id)?;
|
||||||
Ok(items_with_id)
|
Ok(items_with_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,34 @@
|
|||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
pub enum LibraryItemType {
|
pub enum LibraryItemType {
|
||||||
VIDEO,
|
VIDEO,
|
||||||
FOLDER
|
FOLDER
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct LibraryItem {
|
pub struct LibraryItem {
|
||||||
pub id: Uuid,
|
pub id: Uuid,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub r#type: LibraryItemType,
|
pub r#type: LibraryItemType,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ReadLibraryItem {
|
#[derive(Clone)]
|
||||||
|
pub struct LibraryRawItem {
|
||||||
pub id: Option<Uuid>,
|
pub id: Option<Uuid>,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub r#type: LibraryItemType,
|
pub r#type: LibraryItemType,
|
||||||
}
|
}
|
||||||
impl ReadLibraryItem {
|
impl LibraryRawItem {
|
||||||
|
pub fn new(id: Option<Uuid>, name: String, r#type: LibraryItemType) -> Self {
|
||||||
|
Self { id, name, r#type }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn map_to_library_item(&self) -> LibraryItem {
|
pub fn map_to_library_item(&self) -> LibraryItem {
|
||||||
LibraryItem {
|
LibraryItem {
|
||||||
id: self.id.unwrap_or(Uuid::new_v4()),
|
id: self.id.unwrap_or(Uuid::new_v4()),
|
||||||
name: self.name,
|
name: self.name.clone(),
|
||||||
r#type: self.r#type,
|
r#type: self.r#type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use crate::video::error::VideoError;
|
use crate::video::error::VideoError;
|
||||||
use crate::video::model::library_item::{LibraryItem, ReadLibraryItem};
|
use crate::video::model::library_item::{LibraryItem, LibraryRawItem};
|
||||||
use crate::video::model::video::Video;
|
use crate::video::model::video::Video;
|
||||||
|
|
||||||
pub trait VideoPort: Send + Sync {
|
pub trait VideoPort: Send + Sync {
|
||||||
fn list_root_folder(&self) -> Result<Vec<ReadLibraryItem>, VideoError>;
|
fn list_root_folder(&self) -> Result<Vec<LibraryRawItem>, VideoError>;
|
||||||
fn list_folder(&self, folder_id: Uuid) -> Result<Vec<ReadLibraryItem>, VideoError>;
|
fn list_folder(&self, folder_id: Uuid) -> Result<Vec<LibraryRawItem>, VideoError>;
|
||||||
fn get_video_stream(&self, video_id: Uuid) -> Result<Video, VideoError>;
|
fn get_video_stream(&self, video_id: Uuid) -> Result<Video, VideoError>;
|
||||||
fn save(&self, library_item: &LibraryItem) -> Result<(), VideoError>;
|
fn save(&self, library_item: &LibraryItem) -> Result<(), VideoError>;
|
||||||
|
fn save_all(&self, library_items: &Vec<LibraryItem>) -> Result<(), VideoError>;
|
||||||
fn clone_box(&self) -> Box<dyn VideoPort>;
|
fn clone_box(&self) -> Box<dyn VideoPort>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ extern crate core;
|
|||||||
|
|
||||||
use actix_web::web::ServiceConfig;
|
use actix_web::web::ServiceConfig;
|
||||||
use actix_web::{get, web, HttpResponse, Responder};
|
use actix_web::{get, web, HttpResponse, Responder};
|
||||||
use crate::video::handler::download_file;
|
use crate::video::handler::{download_file, get_root_folder_content};
|
||||||
|
|
||||||
pub mod user;
|
pub mod user;
|
||||||
pub mod video;
|
pub mod video;
|
||||||
@@ -13,7 +13,8 @@ async fn health() -> impl Responder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(cfg: &mut ServiceConfig) {
|
pub fn init(cfg: &mut ServiceConfig) {
|
||||||
cfg.service(download_file);
|
cfg.service(download_file)
|
||||||
|
.service(get_root_folder_content);
|
||||||
cfg.default_service(web::to(not_found));
|
cfg.default_service(web::to(not_found));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
use actix_web::{get, HttpResponse, Responder};
|
use std::sync::Arc;
|
||||||
|
use actix_web::{get, web, HttpResponse, Responder};
|
||||||
use tokio::fs::File;
|
use tokio::fs::File;
|
||||||
use tokio_util::codec::{BytesCodec, FramedRead};
|
use tokio_util::codec::{BytesCodec, FramedRead};
|
||||||
use futures_util::stream::StreamExt;
|
use futures_util::stream::StreamExt;
|
||||||
|
use lumiere_application::video::service::VideoService;
|
||||||
|
use lumiere_domain::video::error::VideoError;
|
||||||
|
use lumiere_domain::video::model::library_item::LibraryItem;
|
||||||
|
use crate::video::model::LibraryItemDto;
|
||||||
|
|
||||||
#[get("/download")]
|
#[get("/download")]
|
||||||
pub async fn download_file() -> impl Responder {
|
pub async fn download_file() -> impl Responder {
|
||||||
@@ -15,3 +20,18 @@ pub async fn download_file() -> impl Responder {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[get("/library")]
|
||||||
|
pub async fn get_root_folder_content(
|
||||||
|
video_service: web::Data<Arc<VideoService>>
|
||||||
|
) -> impl Responder {
|
||||||
|
match video_service.list_root_folder() {
|
||||||
|
Ok(library_items) => {
|
||||||
|
let result: Vec<LibraryItemDto> = library_items.iter()
|
||||||
|
.map(LibraryItemDto::new)
|
||||||
|
.collect();
|
||||||
|
HttpResponse::Ok().json(result)
|
||||||
|
}
|
||||||
|
Err(_) => HttpResponse::InternalServerError().finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
pub mod handler;
|
pub mod handler;
|
||||||
|
pub mod model;
|
||||||
pub mod video_format_content_type_mapper;
|
pub mod video_format_content_type_mapper;
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
use lumiere_domain::video::model::library_item::{LibraryItem, LibraryItemType};
|
||||||
|
use serde::Serialize;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
pub struct LibraryItemDto {
|
||||||
|
pub id: Uuid,
|
||||||
|
pub name: String,
|
||||||
|
pub r#type: String
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LibraryItemDto {
|
||||||
|
pub fn new(library_item: &LibraryItem) -> Self {
|
||||||
|
Self {
|
||||||
|
id: library_item.id.clone(),
|
||||||
|
name: library_item.name.clone(),
|
||||||
|
r#type: Self::map_type_to_string(library_item.r#type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map_type_to_string(r#type: LibraryItemType) -> String {
|
||||||
|
match r#type {
|
||||||
|
LibraryItemType::VIDEO => String::from("VIDEO"),
|
||||||
|
LibraryItemType::FOLDER => String::from("FOLDER")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
use lumiere_domain::video::library_item::VideoFormat;
|
// use lumiere_domain::video::library_item::VideoFormat;
|
||||||
|
//
|
||||||
pub fn map_to_content_type(video_format: &VideoFormat) -> &'static str {
|
// pub fn map_to_content_type(video_format: &VideoFormat) -> &'static str {
|
||||||
match video_format {
|
// match video_format {
|
||||||
VideoFormat::AVI => "video/x-msvideo",
|
// VideoFormat::AVI => "video/x-msvideo",
|
||||||
VideoFormat::MKV => "video/x-matroska",
|
// VideoFormat::MKV => "video/x-matroska",
|
||||||
VideoFormat::MP4 => "video/mp4",
|
// VideoFormat::MP4 => "video/mp4",
|
||||||
VideoFormat::WEBM => "video/webm",
|
// VideoFormat::WEBM => "video/webm",
|
||||||
VideoFormat::UNKNOWN => "application/octet-stream"
|
// VideoFormat::UNKNOWN => "application/octet-stream"
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
@@ -1,9 +1,13 @@
|
|||||||
use lumiere_domain::video::error::VideoError;
|
use lumiere_domain::video::error::VideoError;
|
||||||
use lumiere_domain::video::model::library_item::{LibraryItem, ReadLibraryItem};
|
use lumiere_domain::video::model::library_item::{LibraryItem, LibraryItemType, LibraryRawItem};
|
||||||
use lumiere_domain::video::model::video::Video;
|
use lumiere_domain::video::model::video::Video;
|
||||||
use lumiere_domain::video::port::VideoPort;
|
use lumiere_domain::video::port::VideoPort;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
use std::env;
|
||||||
|
use std::fs;
|
||||||
|
use std::fs::DirEntry;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct VideoAdapter {
|
pub struct VideoAdapter {
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -13,84 +17,60 @@ impl VideoAdapter {
|
|||||||
Self {}
|
Self {}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_root_folder_read_library_items(&self) -> Result<Vec<ReadLibraryItem>, VideoError> {
|
fn get_root_folder_read_library_items(&self) -> Result<Vec<LibraryRawItem>, VideoError> {
|
||||||
use std::env;
|
let root_folder = env::var("ROOT_FOLDER").map_err(|_| VideoError::FolderBrowsingTechnicalIssue)?;
|
||||||
use std::fs;
|
|
||||||
|
|
||||||
// Get the root_folder path from environment variable
|
let root_folder_files = fs::read_dir(root_folder)
|
||||||
let root_folder = env::var("ROOT_FOLDER").map_err(|_| VideoError::ConfigurationError("ROOT_FOLDER environment variable not set"))?;
|
.map_err(|_| VideoError::FolderBrowsingTechnicalIssue)?;
|
||||||
|
|
||||||
// List all elements inside this folder on the file system
|
root_folder_files.into_iter()
|
||||||
let entries = fs::read_dir(root_folder)
|
.map(|file_entry|
|
||||||
.map_err(|e| VideoError::FileSystemError(e.to_string()))?;
|
file_entry.map_err(|_| VideoError::FolderBrowsingTechnicalIssue)
|
||||||
|
.and_then(Self::map_file_into_library_raw_item)
|
||||||
// Map all those elements into ReadLibraryItem objects
|
)
|
||||||
let mut items: Vec<ReadLibraryItem> = Vec::new();
|
.collect()
|
||||||
for entry in entries {
|
|
||||||
let entry = entry.map_err(|e| VideoError::FileSystemError(e.to_string()))?;
|
|
||||||
let path = entry.path();
|
|
||||||
|
|
||||||
// Determine if it's a file or directory
|
|
||||||
let is_dir = path.is_dir();
|
|
||||||
let item_type = if is_dir {
|
|
||||||
lumiere_domain::video::model::library_item::LibraryItemType::FOLDER
|
|
||||||
} else {
|
|
||||||
lumiere_domain::video::model::library_item::LibraryItemType::VIDEO
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create ReadLibraryItem with None for ID (will be generated later)
|
|
||||||
let item = ReadLibraryItem {
|
|
||||||
id: None,
|
|
||||||
name: entry.file_name().to_string_lossy().into_owned(),
|
|
||||||
r#type: item_type,
|
|
||||||
};
|
|
||||||
|
|
||||||
items.push(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(items)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_all_library_items_from_db(&self) -> Result<Vec<ReadLibraryItem>, VideoError> {
|
fn map_file_into_library_raw_item(file: DirEntry) -> Result<LibraryRawItem, VideoError> {
|
||||||
todo!()
|
let item_type = if file.path().is_dir() {
|
||||||
|
LibraryItemType::FOLDER
|
||||||
|
} else {
|
||||||
|
LibraryItemType::VIDEO
|
||||||
|
};
|
||||||
|
|
||||||
|
let library_raw_item = LibraryRawItem::new(None, file.file_name().to_string_lossy().into_owned(), item_type);
|
||||||
|
Ok(library_raw_item)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_all_library_items_from_db(&self) -> Result<Vec<LibraryRawItem>, VideoError> {
|
||||||
|
Ok(vec!())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn merge_item_lists(file_system_items: Vec<LibraryRawItem>, db_items: Vec<LibraryRawItem>) -> Vec<LibraryRawItem> {
|
||||||
|
let file_system_items_which_are_not_in_database: Vec<LibraryRawItem> = file_system_items.into_iter()
|
||||||
|
.filter(|file_system_item| !Self::does_item_belong_to_db_items(&db_items, &file_system_item))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
db_items.into_iter().chain(file_system_items_which_are_not_in_database).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn does_item_belong_to_db_items(database_items: &Vec<LibraryRawItem>, file_system_item: &LibraryRawItem) -> bool {
|
||||||
|
database_items.iter()
|
||||||
|
.any(|database_item| database_item.id == file_system_item.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VideoPort for VideoAdapter {
|
impl VideoPort for VideoAdapter {
|
||||||
fn list_root_folder(&self) -> Result<Vec<ReadLibraryItem>, VideoError> {
|
fn list_root_folder(&self) -> Result<Vec<LibraryRawItem>, VideoError> {
|
||||||
use std::thread;
|
|
||||||
|
|
||||||
// In parallel: call both methods
|
|
||||||
let file_system_items = self.get_root_folder_read_library_items()?;
|
let file_system_items = self.get_root_folder_read_library_items()?;
|
||||||
let db_items = self.get_all_library_items_from_db()?;
|
let db_items = self.get_all_library_items_from_db()?;
|
||||||
|
|
||||||
// Merge the two lists. If an item from files has the same id as one from DB, use the DB version
|
let merged = Self::merge_item_lists(file_system_items, db_items);
|
||||||
let mut merged: Vec<ReadLibraryItem> = Vec::new();
|
|
||||||
|
|
||||||
// First add all DB items (they have IDs)
|
|
||||||
for db_item in db_items {
|
|
||||||
merged.push(db_item);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Then add file system items only if they don't exist in DB
|
|
||||||
for fs_item in file_system_items {
|
|
||||||
let exists_in_db = merged.iter().any(|db_item| {
|
|
||||||
if let Some(fs_id) = fs_item.id {
|
|
||||||
db_item.id == Some(fs_id)
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if !exists_in_db {
|
|
||||||
merged.push(fs_item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(merged)
|
Ok(merged)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_folder(&self, folder_id: Uuid) -> Result<Vec<ReadLibraryItem>, VideoError> {
|
fn list_folder(&self, folder_id: Uuid) -> Result<Vec<LibraryRawItem>, VideoError> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,11 +78,15 @@ impl VideoPort for VideoAdapter {
|
|||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save(&self, library_item: LibraryItem) -> Result<(), VideoError> {
|
fn save(&self, library_item: &LibraryItem) -> Result<(), VideoError> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn save_all(&self, library_items: &Vec<LibraryItem>) -> Result<(), VideoError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn clone_box(&self) -> Box<dyn VideoPort> {
|
fn clone_box(&self) -> Box<dyn VideoPort> {
|
||||||
todo!()
|
Box::new(self.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,7 @@ use std::io::{Error, ErrorKind};
|
|||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use lumiere_application::configuration::service::ConfigurationService;
|
use lumiere_application::configuration::service::ConfigurationService;
|
||||||
use lumiere_application::user::service::UserService;
|
use lumiere_application::user::service::UserService;
|
||||||
|
use lumiere_application::video::service::VideoService;
|
||||||
use lumiere_infrastructure::common::database_connection::DatabaseConnection;
|
use lumiere_infrastructure::common::database_connection::DatabaseConnection;
|
||||||
use lumiere_infrastructure::common::database_initialisation::initialise_database_tables;
|
use lumiere_infrastructure::common::database_initialisation::initialise_database_tables;
|
||||||
use lumiere_infrastructure::configuration::adapter::ConfigurationSqliteAdapter;
|
use lumiere_infrastructure::configuration::adapter::ConfigurationSqliteAdapter;
|
||||||
@@ -16,11 +17,13 @@ use lumiere_infrastructure::user::adapter::UserSqliteAdapter;
|
|||||||
use lumiere_infrastructure::user::diesel_adapter::UserDieselAdapter;
|
use lumiere_infrastructure::user::diesel_adapter::UserDieselAdapter;
|
||||||
use lumiere_infrastructure::user::diesel_repository::UserDieselRepository;
|
use lumiere_infrastructure::user::diesel_repository::UserDieselRepository;
|
||||||
use lumiere_infrastructure::user::repository::UserSqliteRepository;
|
use lumiere_infrastructure::user::repository::UserSqliteRepository;
|
||||||
|
use lumiere_infrastructure::video::adapter::VideoAdapter;
|
||||||
|
|
||||||
pub struct ApplicationContext {
|
pub struct ApplicationContext {
|
||||||
pub database_connection: Arc<Mutex<Connection>>,
|
pub database_connection: Arc<Mutex<Connection>>,
|
||||||
pub configuration_service: ConfigurationService,
|
pub configuration_service: ConfigurationService,
|
||||||
pub user_service: UserService,
|
pub user_service: UserService,
|
||||||
|
pub video_service: VideoService,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ApplicationContext {
|
impl ApplicationContext {
|
||||||
@@ -57,10 +60,14 @@ impl ApplicationContext {
|
|||||||
// let user_adapter = Box::new(UserSqliteAdapter::new(user_repository.clone()));
|
// let user_adapter = Box::new(UserSqliteAdapter::new(user_repository.clone()));
|
||||||
let user_service = UserService::new(configuration_service.clone(), user_adapter.clone());
|
let user_service = UserService::new(configuration_service.clone(), user_adapter.clone());
|
||||||
|
|
||||||
|
let video_adapter = Box::new(VideoAdapter::new());
|
||||||
|
let video_service = VideoService::new(video_adapter.clone());
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
database_connection: arc_mutex_connection.clone(),
|
database_connection: arc_mutex_connection.clone(),
|
||||||
configuration_service,
|
configuration_service,
|
||||||
user_service,
|
user_service,
|
||||||
|
video_service,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ use std::io::{BufReader, Error};
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use lumiere_exposition::init;
|
use lumiere_exposition::init;
|
||||||
use lumiere_exposition::video::video_format_content_type_mapper::map_to_content_type;
|
|
||||||
use lumiere_infrastructure::video::video_format_detector::get_content_type;
|
use lumiere_infrastructure::video::video_format_detector::get_content_type;
|
||||||
use tokio_cron_scheduler::{Job, JobScheduler};
|
use tokio_cron_scheduler::{Job, JobScheduler};
|
||||||
|
|
||||||
@@ -35,6 +34,7 @@ async fn main() -> std::io::Result<()> {
|
|||||||
let server = HttpServer::new(
|
let server = HttpServer::new(
|
||||||
move || App::new().configure(init)
|
move || App::new().configure(init)
|
||||||
.app_data(web::Data::new(Arc::new(application_context.user_service.clone())))
|
.app_data(web::Data::new(Arc::new(application_context.user_service.clone())))
|
||||||
|
.app_data(web::Data::new(Arc::new(application_context.video_service.clone())))
|
||||||
)
|
)
|
||||||
.bind("0.0.0.0:19000")
|
.bind("0.0.0.0:19000")
|
||||||
// .bind_rustls_0_23(("0.0.0.0", 19000), tls_config)
|
// .bind_rustls_0_23(("0.0.0.0", 19000), tls_config)
|
||||||
|
|||||||
Reference in New Issue
Block a user