Navid Nikaein

153 papers A* 8A 4B 32C 3Misc 1Journal 50Unranked 55
YearRankTypeTitle / Venue / Authors
2026 J jnl
Comput. Networks
Ilias Chatzistefanidis, Navid Nikaein, Andrea Leone, Ali Maatouk, Leandros Tassiulas, Roberto Morabito, Ioannis Pitsiorlas, Marios Kountouris
2025 J jnl
CoRR
Ilias Chatzistefanidis, Navid Nikaein, Andrea Leone, Ali Maatouk, Leandros Tassiulas, Roberto Morabito, Ioannis Pitsiorlas, Marios Kountouris
2025 J jnl
Comput. Networks
Florian Kaltenberger, Tommaso Melodia, Irfan Ghauri, Michele Polese, Raymond Knopp, Nguyen Tien Thinh, Sakthivel Velumani, Davide Villa, Leonardo Bonati, Robert Schmidt, Sagar Arora, Mikel Irazabal, Navid Nikaein
2025 J jnl
CoRR
Chieh-Chun Chen, Chia-Yu Chang, Navid Nikaein
2025 J jnl
IEEE Netw.
Chieh-Chun Chen, Chia-Yu Chang, Navid Nikaein
2025 J jnl
CoRR
Adnan Shahid, Adrian Kliks, Ahmed Al-Tahmeesschi, Ahmed Elbakary, Alexandros Nikou, Ali Maatouk, Ali Mokh, Amirreza Kazemi, Antonio De Domenico, Athanasios Karapantelakis, Bo Cheng, Bo Yang, Bohao Wang, Carlo Fischione, Chao Zhang, Chaouki Ben Issaid, Chau Yuen, Chenghui Peng, Chongwen Huang, Christina Chaccour, Christo Kurisummoottil Thomas, Dheeraj Sharma, Dimitris Kalogiros, Dusit Niyato, Eli De Poorter, Elissa Mhanna, Emilio Calvanese Strinati, Faouzi Bader, Fathi Abdeldayem, Fei Wang, Fenghao Zhu, Gianluca Fontanesi, Giovanni Geraci, Haibo Zhou, Hakimeh Purmehdi, Hamed Ahmadi, Hang Zou, Hongyang Du, Hoon Lee, Howard H. Yang, Iacopo Poli, Igor Carron, Ilias Chatzistefanidis, Inkyu Lee, Ioannis Pitsiorlas, Jaron Fontaine, Jiajun Wu, Jie Zeng, Jinan Li, Jinane Karam, Johny Gemayel, Juan Deng, Julien Frison, Kaibin Huang, Kehai Qiu, Keith Ball, Kezhi Wang, Kun Guo, Leandros Tassiulas, Lecorve Gwenole, Liexiang Yue, Lina Bariah, Louis Powell, Marcin Dryjanski, Maria Amparo Canaveras Galdon, Marios Kountouris, Maryam Hafeez, Maxime Elkael, Mehdi Bennis, Mehdi Ahmed Boudjelli, Meiling Dai, Mérouane Debbah, Michele Polese, Mohamad Assaad, Mohamed Benzaghta, Mohammad Al Refai, Moussab Djerrab, Mubeen Syed, Muhammad Amir, Na Yan, Najla Alkaabi, Nan Li, Nassim Sehad, Navid Nikaein, Omar Hashash, Pawel Sroka, Qianqian Yang, Qiyang Zhao, Rasoul Nikbakht Silab, Rex Ying, Roberto Morabito, Rongpeng Li, Ryad Madi, Salah Eddine El Ayoubi, Salvatore D'Oro, Samson Lasaulce, Serveh Shalmashi, Sige Liu, Sihem Cherrared, Swarna Bindu Chetty, Swastika Dutta, Syed A. R. Zaidi, Tianjiao Chen, Timothy Murphy, Tommaso Melodia, Tony Q. S. Quek, Vishnu Ram, Walid Saad, Wassim Hamidouche, Weilong Chen, Xiaoou Liu, Xiaoxue Yu, Xijun Wang, Xingyu Shang, Xinquan Wang, Xuelin Cao, Yang Su, Yanping Liang, Yansha Deng, Yifan Yang, Yingping Cui, Yu Sun, Yuxuan Chen, Yvan Pointurier, Zeinab Nehme, Zeinab Nezami, Zhaohui Yang, Zhaoyang Zhang, Zhe Liu, Zhenyu Yang, Zhu Han, Zhuang Zhou, Zihan Chen, Zirui Chen, Zitao Shuai
2025 J jnl
CoRR
Ilias Chatzistefanidis, Andrea Leone, Ali Yaghoubian, Mikel Irazabal, Nassim Sehad, Lina Bariah, Mérouane Debbah, Navid Nikaein
2025 J jnl
CoRR
Ilias Chatzistefanidis, Navid Nikaein
2025 J jnl
Comput. Networks
Ilias Chatzistefanidis, Navid Nikaein
2024 J jnl
Sensors
Wilfrid Azariah, Fransiscus Asisi Bimo, Chih-Wei Lin, Ray-Guang Cheng, Navid Nikaein, Rittwik Jana
2024 J jnl
IEEE J. Sel. Areas Commun.
Alireza Mohammadi, Navid Nikaein
2024 J jnl
CoRR
Florian Kaltenberger, Tommaso Melodia, Irfan Ghauri, Michele Polese, Raymond Knopp, Nguyen Tien Thinh, Sakthivel Velumani, Davide Villa, Leonardo Bonati, Robert Schmidt, Sagar Arora, Mikel Irazabal, Navid Nikaein
2024 J jnl
IEEE Netw. Lett.
Ilias Chatzistefanidis, Andrea Leone, Navid Nikaein
2024 conf
AIAI (Workshops)
Jesús Gutiérrez, Vladica Sark, Mert Özates, Anna Tzanakaki, Markos P. Anastasopoulos, Valerio Frascolla, Ioanna Mesogiti, Elina Theodoropoulou, George L. Lyberopoulos, Luis Díez, Ramón Agüero, Ignacio Santamaría, Padmanava Sen, Simon Pryor, Shahid Mumtaz, Salvatore Pontarelli, Federico Trombetti, Novella Bartolini, Eduard A. Jorswieck, Xi Ding, Navid Nikaein
2024 J jnl
Comput. Networks
Theodoros Tsourdinis, Ilias Chatzistefanidis, Nikos Makris, Thanasis Korakis, Navid Nikaein, Serge Fdida
2024 J jnl
IEEE J. Sel. Areas Commun.
Mikel Irazabal, Navid Nikaein
2023 conf
OFC
Petros Georgiadis, Markos P. Anastasopoulos, Alexandros-Ioannis Manolopoulos, Victoria-Maria Alevizaki, Navid Nikaein, Anna Tzanakaki
2023 conf
ICC
Chieh-Chun Chen, Mikel Irazabal, Chia-Yu Chang, Alireza Mohammadi, Navid Nikaein
2023 B conf
GLOBECOM
Chieh-Chun Chen, Chia-Yu Chang, Navid Nikaein
2023 A* conf
MobiCom
Ta Dang Khoa Le, Navid Nikaein
2023 conf
CSCN
Tao Chen, Slawomir Kuklinski, Emmanouil Pateromichelakis, Konstantinos Samdanis, Akis Kourtis, Navid Nikaein, Antonio F. Skarmeta
2022 J jnl
CoRR
Wilfrid Azariah, Fransiscus Asisi Bimo, Chih-Wei Lin, Ray-Guang Cheng, Rittwik Jana, Navid Nikaein
2022 J jnl
IEEE Trans. Mob. Comput.
Mikel Irazabal, Elena López-Aguilera, Ilker Demirkol, Navid Nikaein
2022 J jnl
IEEE Access
Chia-Yu Chang, Navid Nikaein, Thrasyvoulos Spyropoulos, Koen De Schepper
2021 A conf
CoNEXT
Robert Schmidt, Mikel Irazabal, Navid Nikaein
2021 J jnl
IEEE Access
Sushmit Bhattacharjee, Kostas Katsalis, Osama Arouk, Robert Schmidt, Tongtong Wang, Xueli An, Thomas Bauschert, Navid Nikaein
2021 J jnl
IEEE Access
Mikel Irazabal, Elena López-Aguilera, Ilker Demirkol, Robert Schmidt, Navid Nikaein
2021 J jnl
IEEE Trans. Netw. Serv. Manag.
Robert Schmidt, Navid Nikaein
2020 B conf
NOMS
Osama Arouk, Navid Nikaein
2020 B conf
NOMS
Robert Schmidt, Navid Nikaein
2020 B conf
NOMS
Xenofon Vasilakos, Berkay Köksal, Dwi Hartati Izaldi, Navid Nikaein, Robert Schmidt, Nasim Ferdosian, Riri Fitri Sari, Ray-Guang Cheng
2020 J jnl
CoRR
Xenofon Vasilakos, Navid Nikaein, Dean H. Lorenz, Berkay Köksal, Nasim Ferdosian
2020 B conf
GLOBECOM
Osama Arouk, Navid Nikaein
2020 B conf
GLOBECOM
Chieh-Chun Chen, Ray-Guang Cheng, Chung-Yin Ho, Matthieu Kanj, Bruno Mongazon-Cazavet, Navid Nikaein
2020 J jnl
CoRR
Chieh-Chun Chen, Ray-Guang Cheng, Chung-Yin Ho, Matthieu Kanj, Bruno Mongazon-Cazavet, Navid Nikaein
2020 A* conf
MobiCom
Robert Schmidt, Navid Nikaein
2020 conf
ICC
Sushmit Bhattacharjee, Robert Schmidt, Kostas Katsalis, Chia-Yu Chang, Thomas Bauschert, Navid Nikaein
2019 J jnl
IEEE Trans. Broadcast.
Qi Wang, José M. Alcaraz Calero, Ruben Ricart-Sanchez, Maria Barros Weiss, Anastasius Gavras, Navid Nikaein, Xenofon Vasilakos, Giacomo Bernini, Pietro G. Giardina, Mark Roddy, Michael Healy, Paul Walsh, Thuy Truong, Zdravko Bozakov, Konstantinos Koutsopoulos, Pedro Neves, Cristian Patachia-Sultanoiu, Marius Iordache, Elena-Madalina Oproiu, Imen Grida Ben Yahia, Ciriaco Angelo, Cosimo Zotti, Giuseppe Celozzi, Donal Morris, Ricardo Figueiredo, Dean H. Lorenz, Salvatore Spadaro, George Agapiou, Ana Cristina Aleixo, Cipriano Lomba
2019 conf
ICC
Robert Schmidt, Chia-Yu Chang, Navid Nikaein
2019 C conf
WOWMOM
Delia Ciullo, Thrasyvoulos Spyropoulos, Navid Nikaein, Bruno Jechoux, Giannis Sarantidis
2019 B conf
GLOBECOM
Robert Schmidt, Chia-Yu Chang, Navid Nikaein
2019 B conf
NetSoft
Luca Baldini, Qi Wang, José M. Alcaraz Calero, Maria Barros Weiss, Anastasius Gavras, Giacomo Bernini, Pietro G. Giardina, Ciriaco Angelo, Xenofon Vasilakos, Chia-Yu Chang, Navid Nikaein, Salvatore Spadaro, Albert Pagès, Fernando Agraz, George Agapiou, Thuy Truong, Konstantinos Koutsopoulos, José Cabaça, Ricardo Figueiredo
2019 J jnl
IEEE Netw. Lett.
Konstantinos Alexandris, Chia-Yu Chang, Navid Nikaein
2018 conf
VTC Spring
Dario Sabella, Navid Nikaein, A. Huang, Jetmir Xhembulla, Giovanni Malnati, Salvatore Scarpina
2018 J jnl
IEEE Access
Romain Favraud, Chia-Yu Chang, Navid Nikaein
2018 J jnl
Comput. Networks
Eryk Schiller, Navid Nikaein, Eirini Kalogeiton, Mikael Gasparyan, Torsten Braun
2018 J jnl
IEEE Veh. Technol. Mag.
Chia-Yu Chang, Navid Nikaein
2018 conf
ICC
Nikos Makris, Christos Zarafetas, Pavlos Basaras, Thanasis Korakis, Navid Nikaein, Leandros Tassiulas
2018 conf
ICC
Osama Arouk, Thierry Turletti, Navid Nikaein, Katia Obraczka
2018 conf
INFOCOM Workshops
Ray-Guang Cheng, Raymond Knopp, Chung-Yin Ho, Kai-Hsiang Hsu, Tian-Jen Liu, Wei-Tai Chen, Bing-Zhi Hsieh, Matthieu Kanj, François Taburet, Navid Nikaein
2018 conf
DSP
Chin-Ya Huang, Chung-Yin Ho, Navid Nikaein, Ray-Guang Cheng
2018 B conf
NOMS
Kostas Katsalis, Navid Nikaein, Anta Huang
2018 A* conf
INFOCOM
Nikolaos Sapountzis, Thrasyvoulos Spyropoulos, Navid Nikaein, Umer Salim
2018 conf
CloudNet
Navid Nikaein, Xenofon Vasilakos, Anta Huang
2018 J jnl
Comput. Commun. Rev.
Navid Nikaein, Chia-Yu Chang, Konstantinos Alexandris
2018 B conf
WCNC
Konstantinos Alexandris, Chia-Yu Chang, Navid Nikaein, Thrasyvoulos Spyropoulos
2018 A conf
MobiSys
Navid Nikaein, Chia-Yu Chang, Robert Schmidt, Shahab Shariat, Konstantinos Alexandris, Xenofon Vasilakos
2018 J jnl
IEEE Netw.
Adlen Ksentini, Pantelis A. Frangoudis, Amogh PC, Navid Nikaein
2018 J jnl
IEEE Access
Chia-Yu Chang, Navid Nikaein
2018 conf
INFOCOM Workshops
Chia-Yu Chang, Navid Nikaein, Thrasyvoulos Spyropoulos
2018 J jnl
IEEE Commun. Mag.
Chia-Yu Chang, Navid Nikaein, Osama Arouk, Kostas Katsalis, Adlen Ksentini, Thierry Turletti, Konstantinos Samdanis
2018 conf
BMSB
Qi Wang, José M. Alcaraz Calero, Maria Barros Weiss, Anastasius Gavras, Pedro Miguel Neves, Rui Calé, Giacomo Bernini, Gino Carrozzo, Nicola Ciulli, Giuseppe Celozzi, Ciriaco Angelo, Anna Levin, Dean H. Lorenz, Katherine Barabash, Navid Nikaein, Salvatore Spadaro, Donal Morris, Ioannis P. Chochliouros, Yiorgos Agapiou, Cristian Patachia, Marius Iordache, Elena-Madalina Oproiu, Cipriano Lomba, Ana Cristina Aleixo, Alberto Ro-Drigues, Ger Hallissey, Zdravko Bozakov, Konstantinos Koutsopoulos, Paul Walsh
2018 B conf
GLOBECOM
Chia-Yu Chang, Lukasz Kulacz, Robert Schmidt, Adrian Kliks, Navid Nikaein
2017 conf
VTC Fall
Romain Favraud, Navid Nikaein
2017 A* conf
MobiCom
Xenofon Foukas, Navid Nikaein, Mohamed M. Kassem, Mahesh K. Marina, Kimon P. Kontovasilis
2017 A* conf
MobiCom
Anta Huang, Navid Nikaein
2017 conf
ICC Workshops
Alexandros Kostopoulos, Ioannis P. Chochliouros, Fang-Chun Kuo, Roberto Riggio, Leonardo Goratti, Navid Nikaein, Ioannis Giannoulakis, Jordi Pérez-Romero, Tao Chen, Rebecca Steinert, Dorin Panaitopol
2017 conf
ICC
Nikos Makris, Pavlos Basaras, Thanasis Korakis, Navid Nikaein, Leandros Tassiulas
2017 Misc conf
COMSNETS
S. Sandeep Kumar, Raymond Knopp, Navid Nikaein, Debashisha Mishra, Bheemarjuna Reddy Tamma, A. Antony Franklin, Kiran Kuchi, Rohit Gupta
2017 conf
ICC
Chia-Yu Chang, Navid Nikaein, Raymond Knopp, Thrasyvoulos Spyropoulos, S. Sandeep Kumar
2017 J jnl
J. Simulation
Bilel Ben Romdhanne, Navid Nikaein
2017 J jnl
Pervasive Mob. Comput.
Cesar A. García-Pérez, Almudena Díaz, Alvaro Rios, Pedro Merino, Kostas Katsalis, Chia-Yu Chang, Shahab Shariat, Navid Nikaein, Pilar Rodriguez, Donal Morris
2017 conf
ICC
Anta Huang, Navid Nikaein, Tore Stenbock, Adlen Ksentini, Christian Bonnet
2017 J jnl
EURASIP J. Wirel. Commun. Netw.
Sina Khatibi, Luisa Caeiro, Lucio Studer Ferreira, Luís M. Correia, Navid Nikaein
2017 conf
CloudNet
Osama Arouk, Thierry Turletti, Navid Nikaein
2017 J jnl
IEEE Commun. Mag.
Kostas Katsalis, Navid Nikaein, Eryk Schiller, Adlen Ksentini, Torsten Braun
2017 B conf
GLOBECOM
Romain Favraud, Navid Nikaein, Chia-Yu Chang
2017 J jnl
IEEE Commun. Mag.
Junquan Deng, Olav Tirkkonen, Ragnar Freij-Hollanti, Tao Chen, Navid Nikaein
2017 conf
EuCNC
Junquan Deng, Olav Tirkkonen, Tao Chen, Navid Nikaein
2017 B conf
WiMob
Romain Favraud, Chia-Yu Chang, Navid Nikaein
2017 J jnl
IEEE Commun. Mag.
Adlen Ksentini, Navid Nikaein
2017 J jnl
IEEE/ACM Trans. Netw.
Nikolaos Sapountzis, Thrasyvoulos Spyropoulos, Navid Nikaein, Umer Salim
2017 conf
VTC Fall
Konstantinos Alexandris, Chia-Yu Chang, Kostas Katsalis, Navid Nikaein, Thrasyvoulos Spyropoulos
2016 conf
ICC Workshops
Kostas Katsalis, Navid Nikaein, Eryk Schiller, Romain Favraud, Torsten Ingo Braun
2016 J jnl
IEEE Trans. Veh. Technol.
Lusheng Wang, Fei Fang, Navid Nikaein, Laura Cottatellucci
2016 B conf
WiOpt
Konstantinos Alexandris, Navid Nikaein, Raymond Knopp, Christian Bonnet
2016 A conf
CoNEXT
Xenofon Foukas, Navid Nikaein, Mohamed M. Kassem, Mahesh K. Marina, Kimon P. Kontovasilis
2016 B conf
GLOBECOM
Chia-Yu Chang, Navid Nikaein, Thrasyvoulos Spyropoulos
2016 conf
ICC
Chia-Yu Chang, Ruggero Schiavi, Navid Nikaein, Thrasyvoulos Spyropoulos, Christian Bonnet
2016 J jnl
Ad Hoc Sens. Wirel. Networks
Milica Popovic, Dejan Drajic, Philipp Svoboda, Navid Nikaein, Srdan Krco, Markus Laner
2016 B conf
WCNC
Konstantinos Alexandris, Nikolaos Sapountzis, Navid Nikaein, Thrasyvoulos Spyropoulos
2016 conf
MobiArch
Chia-Yu Chang, Konstantinos Alexandris, Navid Nikaein, Kostas Katsalis, Thrasyvoulos Spyropoulos
2016 conf
IUCC-CSS
Kostas Katsalis, Navid Nikaein, Andy Edmonds
2016 A* conf
INFOCOM
Nikolaos Sapountzis, Thrasyvoulos Spyropoulos, Navid Nikaein, Umer Salim
2016 conf
EuCNC
Cesar A. García-Pérez, Alvaro Rios, Pedro Merino, Kostas Katsalis, Navid Nikaein, Ricardo Figueiredo, Donal Morris, Terry O'Callaghan
2016 J jnl
EURASIP J. Wirel. Commun. Netw.
Kaijie Zhou, Navid Nikaein
2016 B conf
CLOUD
Kostas Katsalis, Thanasis G. Papaioannou, Navid Nikaein, Leandros Tassiulas
2016 conf
ICT
Alexandros Kostopoulos, George Agapiou, Fang-Chun Kuo, Kostas Pentikousis, Antonio Maria Cipriano, Dorin Panaitopol, Dimitri Marandin, Karol Kowalik, Konstantinos Alexandris, Chia-Yu Chang, Navid Nikaein, Mariana Goldhamer, Adrian Kliks, Rebecca Steinert, Aarne Mämmelä, Tao Chen
2016 J jnl
IEEE Trans. Netw. Serv. Manag.
Bruno Sousa, Luís Cordeiro, Paulo Simões, Andy Edmonds, Santiago Ruiz, Giuseppe A. Carella, Marius Corici, Navid Nikaein, Andre S. Gomes, Eryk Schiller, Torsten Braun, Thomas Michael Bohnert
2016 J jnl
IEEE Commun. Mag.
Romain Favraud, Apostolos Apostolaras, Navid Nikaein, Thanasis Korakis
2015 B conf
SECON
Apostolos Apostolaras, Navid Nikaein, Raymond Knopp, Antonio Maria Cipriano, Thanasis Korakis, Iordanis Koutsopoulos, Leandros Tassiulas
2015 B conf
GLOBECOM
Nikolaos Sapountzis, Thrasyvoulos Spyropoulos, Navid Nikaein, Umer Salim
2015 conf
ICC
Islam Alyafawi, Eryk Schiller, Torsten Braun, Desislava C. Dimitrova, Andre S. Gomes, Navid Nikaein
2015 A* conf
MobiCom
Navid Nikaein, Raymond Knopp, Lionel Gauthier, Eryk Schiller, Torsten Braun, Dominique Pichon, Christian Bonnet, Florian Kaltenberger, Dominique Nussbaum
2015 B conf
SECON
Apostolos Apostolaras, Navid Nikaein, Raymond Knopp, Antonio Maria Cipriano, Thanasis Korakis, Iordanis Koutsopoulos, Leandros Tassiulas
2015 conf
ICC
Kaijie Zhou, Navid Nikaein
2015 conf
MobiArch
Navid Nikaein, Eryk Schiller, Romain Favraud, Kostas Katsalis, Donatos Stavropoulos, Islam Alyafawi, Zhongliang Zhao, Torsten Braun, Thanasis Korakis
2015 conf
MCS@MobiCom
Navid Nikaein
2015 conf
MILCOM
Romain Favraud, Navid Nikaein
2014 conf
WF-IoT
Soumya Kanti Datta, Christian Bonnet, Navid Nikaein
2014 conf
ISSNIP
Soumya Kanti Datta, Christian Bonnet, Navid Nikaein
2014 A* conf
MobiCom
Navid Nikaein, Raymond Knopp, Florian Kaltenberger, Lionel Gauthier, Christian Bonnet, Dominique Nussbaum, Riadh Ghaddab
2014 J jnl
Comput. Commun. Rev.
Navid Nikaein, Mahesh K. Marina, Saravana Manickam, Alex Dawson, Raymond Knopp, Christian Bonnet
2014 conf
WMNC
Soumya Kanti Datta, Christian Bonnet, Navid Nikaein
2014 B conf
WCNC
Ankit Bhamri, Navid Nikaein, Florian Kaltenberger, Jyri Hämäläinen, Raymond Knopp
2014 B conf
GLOBECOM
Nikolaos Sapountzis, Stylianos Sarantidis, Thrasyvoulos Spyropoulos, Navid Nikaein, Umer Salim
2014 B conf
IWCMC
Soumya Kanti Datta, Christian Bonnet, Navid Nikaein
2014 conf
VTC Spring
Ankit Bhamri, Navid Nikaein, Florian Kaltenberger, Jyri Hämäläinen, Raymond Knopp
2014 C conf
ICCC
Lusheng Wang, Fei Fang, Kewei Min, Navid Nikaein, Laura Cottatellucci
2014 conf
ICCE-Berlin
Soumya Kanti Datta, Christian Bonnet, Navid Nikaein
2013 conf
SimuTools
Aymen Hafsaoui, Navid Nikaein, Christian Bonnet
2013 J jnl
IEEE Trans. Wirel. Commun.
Lusheng Wang, Claire Goursaud, Navid Nikaein, Laura Cottatellucci, Jean-Marie Gorce
2013 conf
SimuTools
Bilel Ben Romdhanne, Navid Nikaein, Christian Bonnet
2013 B conf
WCNC
Kaijie Zhou, Navid Nikaein, Raymond Knopp
2013 conf
SIGSIM-PADS
Bilel Ben Romdhanne, Mohamed Said Mosli Bouksiaa, Navid Nikaein, Christian Bonnet
2013 conf
LCN Workshops
Ngoc-Duy Nguyen, Raymond Knopp, Navid Nikaein, Christian Bonnet
2013 J jnl
IEEE Wirel. Commun. Lett.
Kaijie Zhou, Navid Nikaein, Thrasyvoulos Spyropoulos
2013 conf
SimuTools
Imran Latif, Florian Kaltenberger, Navid Nikaein, Raymond Knopp
2013 J jnl
Trans. Emerg. Telecommun. Technol.
Carles Antón-Haro, Thierry Lestable, Yonghua Lin, Navid Nikaein, Thomas Watteyne, Jesus Alonso-Zarate
2013 B conf
WCNC
Kaijie Zhou, Navid Nikaein
2013 conf
ISCE
Soumya Kanti Datta, Christian Bonnet, Navid Nikaein
2013 conf
SimuTools
Bilel Ben Romdhanne, Mohamed Said Mosli Bouksiaa, Navid Nikaein, Christian Bonnet
2013 conf
ISWCS
Navid Nikaein, Markus Laner, Kaijie Zhou, Philipp Svoboda, Dejan Drajic, Milica Popovic, Srdjan Krco
2013 B conf
IWCMC
Isabelle Dalmasso, Soumya Kanti Datta, Christian Bonnet, Navid Nikaein
2013 conf
ISWCS
Markus Laner, Philipp Svoboda, Navid Nikaein, Markus Rupp
2012 B conf
WiOpt
Markus Laner, Philipp Svoboda, Peter Romirer-Maierhofer, Navid Nikaein, Fabio Ricciato, Markus Rupp
2012 conf
EUSIPCO
Kaijie Zhou, Tania Villa, Navid Nikaein, Raymond Knopp, Ruben Merz
2012 conf
VTC Spring
Kaijie Zhou, Navid Nikaein, Raymond Knopp, Christian Bonnet
2012 conf
SimuTools
Bilel Ben Romdhanne, Navid Nikaein
2012 C conf
DS-RT
Bilel Ben Romdhanne, Navid Nikaein, Mohamed Said Mosli Bouksiaa
2012 conf
IMIS
Dejan Drajic, Srdjan Krco, Igor Tomic, Milica Popovic, Nenad Zeljkovic, Navid Nikaein, Philipp Svoboda
2012 B conf
WiOpt
Qianrui Li, Lusheng Wang, Laura Cottatellucci, Navid Nikaein
2012 B conf
MASCOTS
Aymen Hafsaoui, Navid Nikaein, Lusheng Wang
2012 conf
WONS
Dejan Drajic, Srdjan Krco, Igor Tomic, Philipp Svoboda, Milica Popovic, Navid Nikaein, Nenad Zeljkovic
2011 conf
EW
Navid Nikaein, Srdjan Krea
2011 B conf
MASS
Daniel Câmara, Christian Bonnet, Navid Nikaein, Michelle Wetterwald
2011 conf
PM2HW2N@MSWiM
Bilel Ben Romdhanne, Navid Nikaein, Raymond Knopp, Christian Bonnet
2010 conf
CrownCom
Oscar Gustafsson, Kiarash Amiri, Dennis Andersson, Anton Blad, Christian Bonnet, Joseph R. Cavallaro, Jeroen Declerck, Antoine Dejonghe, Patrik Eliardsson, Miguel Glassee, Aawatif Hayar, Lieven Hollevoet, Christopher Hunter, Madhura Joshi, Florian Kaltenberger, Raymond Knopp, Khanh Le, Zoran Miljanic, Patrick Murphy, Frederik Naessens, Navid Nikaein, Dominique Nussbaum, Renaud Pacalet, Praveen Raghavan, Ashutosh Sabharwal, Onkar Sarode, Predrag Spasojevic, Yang Sun, Hugo M. Tullberg, Tom Vander Aa, Liesbet Van der Perre, Michelle Wetterwald, Michael Wu
2010 B conf
PIMRC
Daniel Câmara, Christian Bonnet, Navid Nikaein
2006 J jnl
IEEE Commun. Mag.
Rolf Winter, Jochen H. Schiller, Navid Nikaein, Christian Bonnet
2005 A conf
CoNEXT
Jérôme Härri, Navid Nikaein, Christian Bonnet
2004 J jnl
Mob. Networks Appl.
Navid Nikaein, Christian Bonnet
2000 B conf
MobiHoc
Navid Nikaein, Houda Labiod, Christian Bonnet
s3-storage/s3_uploader.py
← Index s3-storage/s3_uploader.py python
# python s3_uploader.py /path/to/files repository_name --notes "Optional notes"
import hashlib
import multiprocessing
from multiprocessing import Pool
import sys
import logging
from logging.handlers import QueueHandler
from datetime import datetime
import os
import time
import json
from enum import Enum
import tempfile
import magic
from typing import Optional, Dict, Any
from dotenv import load_dotenv
from datetime import timezone

# File handling
import py7zr
import pyzipper
from magika import Magika

# S3 and database
from minio import Minio
import clickhouse_connect

load_dotenv(override=True)

class UploadResult(Enum):
    CORRECTLY = 0
    FAILED = 1
    SKIPPED = 2  # For duplicates

class FileNameFormatter(logging.Formatter):
    def format(self, record):
        record.filenameinfo = getattr(record, "filenameinfo", "unknown")
        return super().format(record)

def setup_logger(log_file, filename):
    """Set up a logger for a specific file"""
    logger = logging.getLogger(filename)
    if not logger.handlers:
        if os.getenv("SERVER_ENV") == "prod":
            logger.setLevel(logging.INFO)
        else:
            logger.setLevel(logging.DEBUG)
            
        # Create file handler
        handler = logging.FileHandler(log_file)
        formatter = FileNameFormatter(
            "%(asctime)s - %(filenameinfo)s - %(levelname)s - %(message)s"
        )
        handler.setFormatter(formatter)
        logger.addHandler(handler)
        logger.propagate = False
    return logger

def logger_thread(log_queue, log_file):
    handler = logging.FileHandler(log_file)
    formatter = FileNameFormatter(
        "%(asctime)s - %(filenameinfo)s - %(levelname)s - %(message)s"
    )
    handler.setFormatter(formatter)

    while True:
        try:
            record = log_queue.get()
            if record is None:
                break
            message = formatter.format(record)
            handler.stream.write(message + "\n")
            handler.stream.flush()
        except Exception:
            import traceback
            print("[ERR] Error in logger thread:", file=sys.stderr)
            traceback.print_exc(file=sys.stderr)

def get_s3_key(sha256: str, is_archived: bool, original_ext: str = None) -> str:
    """
    Generate S3 key using sharding pattern with appropriate extension
    
    Args:
        sha256: The file's SHA256 hash
        is_archived: Whether the file was already archived (zip/7z)
        original_ext: The original file extension (if any)
    """
    # If file was already archived, keep its extension
    if is_archived and original_ext and original_ext.lower() in ['.zip', '.7z']:
        extension = original_ext
    else:
        # For files we archived ourselves, use .zip
        extension = '.zip'
        
    return f"{sha256[:2]}/{sha256[2:4]}/{sha256}{extension}"

def process_single_file(args):
    """Independent worker function for processing a single file"""
    filepath, file_number, total_files, config, log_file = args
    filename = os.path.basename(filepath)
    base_logger = setup_logger(log_file, filename)
    extra = {"filenameinfo": filename}
    logger = logging.LoggerAdapter(base_logger, extra)
    s3_client = None
    ch_client = None

    try:
        logger.info(f"Processing file {file_number}/{total_files}: {filepath}")

        # Create connections for this process
        s3_client = Minio(
            config["s3_endpoint"],
            access_key=config["s3_access_key"],
            secret_key=config["s3_secret_key"],
            secure=True
        )
        
        ch_client = clickhouse_connect.get_client(
            host=config['clickhouse_host'],
            port=config['clickhouse_port'],
            username=config['clickhouse_user'],
            password=config['clickhouse_password'],
            database=config['clickhouse_database'],
            verify=config['clickhouse_verify']
        )

        # Process the file and get contents
        ext = os.path.splitext(filepath.lower())[1]
        is_archived = ext in ['.zip', '.7z']

        with tempfile.TemporaryDirectory() as temp_dir:
            try:
                if filename.startswith("."):
                    logger.debug(f"Skipping hidden file: {filename}")
                    return UploadResult.SKIPPED

                elif ext == ".zip":
                    logger.debug(f"Processing ZIP file: {filepath}")
                    with pyzipper.AESZipFile(filepath) as zf:
                        zf.pwd = b"infected"
                        filename = zf.namelist()[0]
                        zf.extractall(temp_dir)
                        extracted_path = os.path.join(temp_dir, filename)
                        
                        with open(extracted_path, "rb") as f:
                            file_content = f.read()
                        with open(filepath, "rb") as f:
                            archive_content = f.read()
                            
                elif ext == ".7z":
                    logger.debug(f"Processing 7z file: {filepath}")
                    with py7zr.SevenZipFile(filepath, mode="r", password="infected") as z:
                        z.extractall(path=temp_dir)
                        # Get first file in the archive
                        for root, _, files in os.walk(temp_dir):
                            if files:
                                filename = files[0]
                                extracted_path = os.path.join(root, filename)
                                break
                                
                        with open(extracted_path, "rb") as f:
                            file_content = f.read()
                        with open(filepath, "rb") as f:
                            archive_content = f.read()
                else:
                    logger.debug(f"Processing non-archived file: {filepath}")
                    # For non-archived files, create password protected zip
                    with open(filepath, "rb") as f:
                        file_content = f.read()
                    filename = os.path.basename(filepath)
                    
                    # Create password protected zip
                    with tempfile.NamedTemporaryFile(delete=False) as temp_zip:
                        with pyzipper.AESZipFile(
                            temp_zip.name,
                            'w',
                            compression=pyzipper.ZIP_LZMA,
                            encryption=pyzipper.WZ_AES
                        ) as zf:
                            zf.pwd = b'infected'
                            zf.writestr(filename, file_content)
                        
                        with open(temp_zip.name, 'rb') as f:
                            archive_content = f.read()
                    
                    os.unlink(temp_zip.name)

                # Calculate hash
                sha256 = hashlib.sha256(file_content).hexdigest()
                # s3_key = f"{sha256[:2]}/{sha256[2:4]}/{sha256}"
                s3_key = get_s3_key(sha256, is_archived, ext if is_archived else None)
                logger.debug(f"Calculated SHA256: {sha256}")

                # Check if exists in S3
                try:
                    s3_client.stat_object(config["s3_bucket"], s3_key)
                    exists = True
                    logger.debug(f"File exists in S3: {s3_key}")
                except:
                    exists = False
                    logger.debug(f"File does not exist in S3: {s3_key}")

                # Prepare metadata
                max_timestamp = int(datetime(9999, 12, 31, 23, 59, 59, tzinfo=timezone.utc).timestamp() * 1000)
                now = datetime.now(timezone.utc)
                now_timestamp = int(now.timestamp() * 1000)
                inverted_timestamp = datetime.fromtimestamp((max_timestamp - now_timestamp)/1000, tz=timezone.utc)


                data = [[
                    sha256,                     # String
                    filename,                   # String
                    config['repository'],       # String
                    len(file_content),         # UInt64
                    magic.from_buffer(file_content),        # String
                    magic.from_buffer(file_content, mime=True),  # String
                    Magika().identify_bytes(file_content).output.ct_label,  # String
                    now,                       # upload_date
                    now,                       # first_seen
                    inverted_timestamp,        # version_date for replacing
                    config['s3_bucket'],       # String
                    s3_key,                    # String
                    config['notes'] if config['notes'] else None  # Nullable(String)
                ]]

                column_names = [
                    'sha256', 'filename', 'repository', 'file_size',
                    'filetype', 'filetype_mime', 'filetype_magika',
                    'upload_date', 'first_seen', 'version_date', 's3_bucket', 's3_key', 'notes'
                ]

                column_type_names = [
                    'String', 'String', 'LowCardinality(String)', 'UInt64',
                    'String', 'String', 'String',
                    'DateTime64(3, \'UTC\')', 'DateTime64(3, \'UTC\')', 
                    'DateTime64(3, \'UTC\')', 'String', 'String', 'Nullable(String)'
                ]
                
                if exists:
                    # Just update database
                    try:
                        ch_client.insert(
                            'samples_catalog',
                            data,
                            column_names=column_names,
                            column_type_names=column_type_names,
                            settings={'input_format_values_interpret_expressions': 0}
                        )
                        logger.info(f"Updated metadata for existing file: {sha256}")
                    except Exception as e:
                        logger.error(f"Error inserting metadata: {str(e)}")
                        import traceback
                        logger.error(f"Full traceback: {traceback.format_exc()}")
                    return UploadResult.SKIPPED
                else:
                    try:    
                        # Upload to S3 and insert metadata
                        import io
                        file_data = io.BytesIO(archive_content)
                        s3_client.put_object(
                            bucket_name=config['s3_bucket'],
                                object_name=s3_key,
                                data=file_data,
                                length=len(archive_content)
                            )
                        logger.info(f"Uploaded to S3: {s3_key}")
                    except Exception as e:
                        logger.error(f"Error uploading to S3: {str(e)}")
                        import traceback
                        logger.error(f"Full traceback: {traceback.format_exc()}")
                        return UploadResult.FAILED
                    
                    try:
                        ch_client.insert(
                            'samples_catalog',
                            data,
                            column_names=column_names,
                            column_type_names=column_type_names,
                            settings={'input_format_values_interpret_expressions': 0}
                        )
                        logger.info(f"Successfully processed file: {sha256}")
                        return UploadResult.CORRECTLY
                    except Exception as e:
                        logger.error(f"Error inserting metadata: {str(e)}")
                        import traceback
                        logger.error(f"Full traceback: {traceback.format_exc()}")
                        return UploadResult.FAILED

            except Exception as e:
                logger.error(f"Error processing file: {str(e)}")
                import traceback
                logger.error(f"Full traceback: {traceback.format_exc()}")
                return UploadResult.FAILED

    except Exception as e:
        logger.error(f"Error in worker: {str(e)}")
        return UploadResult.FAILED
    finally:
        # if s3_client:
        #     s3_client.close()
        if ch_client:
            ch_client.close()
        if base_logger and base_logger.handlers:
            for handler in base_logger.handlers:
                handler.close()
            base_logger.handlers.clear()

class S3Uploader:
    def __init__(self, path: str, repository: str, notes: Optional[str] = None):
        """
        Initialize S3 uploader
        
        Args:
            path: Path to file or directory to process
            repository: Repository name
            notes: Optional notes to add to all files
        """
        self.path = path
        self.repository = repository
        self.notes = notes
        
        # Initialize multiprocessing components
        self.manager = multiprocessing.Manager()
        # self.log_queue = self.manager.Queue()
        self.total_results = self.manager.dict({result: 0 for result in UploadResult})
        
        # Set up logging
        self.today = datetime.today().strftime("%Y%m%dT%H%M%S")
        # self.log_file = os.getenv("LOG_FILE_PATH", "./logs/") + f"{self.today}-{self.repository}-upload.txt"
        log_base_path = os.getenv("LOG_FILE_PATH")
        if not log_base_path:
            log_base_path = os.path.join(os.getcwd(), "logs")  # Default to ./logs directory
        self.log_file = os.path.join(log_base_path, f"{self.today}-{self.repository}-upload.txt")
        os.makedirs(os.path.dirname(self.log_file), exist_ok=True)

        # Initialize S3 client
        self.s3_client = Minio(
            os.getenv("S3_ENDPOINT"),
            access_key=os.getenv("S3_ACCESS_KEY"),
            secret_key=os.getenv("S3_SECRET_KEY"),
            secure=True  # Set to False if not using HTTPS
        )
        self.bucket_name = os.getenv("S3_BUCKET")

        # Initialize ClickHouse client
        self.ch_client = clickhouse_connect.get_client(
            host=os.getenv('CLICKHOUSE_HOST'),
            port=os.getenv('CLICKHOUSE_PORT'),
            username=os.getenv('CLICKHOUSE_USER'),
            password=os.getenv('CLICKHOUSE_PASSWORD'),
            database=os.getenv('CLICKHOUSE_DATABASE'),
            verify=os.getenv('CLICKHOUSE_ENFORCE_SSL', 'False')
        )
        
        # Ensure database table exists
        self._create_table()

    def _create_table(self):
        """Create the file catalog table if it doesn't exist"""
        create_table_query = """
            CREATE TABLE IF NOT EXISTS samples_catalog (
                sha256 String,
                filename String,
                repository LowCardinality(String),
                file_size UInt64,
                filetype String,
                filetype_mime String,
                filetype_magika String,
                upload_date DateTime64(3, 'UTC'),
                first_seen DateTime64(3, 'UTC'),
                version_date DateTime64(3, 'UTC'),  -- This will be inverted timestamp
                s3_bucket String,
                s3_key String,
                notes Nullable(String),
                PRIMARY KEY (sha256, repository)
            ) ENGINE = ReplacingMergeTree(version_date)
            ORDER BY (sha256, repository)
        """
        self.ch_client.command(create_table_query)

    # # def upload(self):
    # #     """Main upload function with multiprocessing support"""
    # #     start_time = time.time()

    # #     config = {
    # #         "s3_endpoint": os.getenv("S3_ENDPOINT"),
    # #         "s3_access_key": os.getenv("S3_ACCESS_KEY"),
    # #         "s3_secret_key": os.getenv("S3_SECRET_KEY"),
    # #         "s3_bucket": os.getenv("S3_BUCKET"),
    # #         "clickhouse_host": os.getenv("CLICKHOUSE_HOST"),
    # #         "clickhouse_port": os.getenv("CLICKHOUSE_PORT"),
    # #         "clickhouse_user": os.getenv("CLICKHOUSE_USER"),
    # #         "clickhouse_password": os.getenv("CLICKHOUSE_PASSWORD"),
    # #         "clickhouse_database": os.getenv("CLICKHOUSE_DATABASE"),
    # #         "clickhouse_verify": os.getenv("CLICKHOUSE_ENFORCE_SSL", "False"),
    # #         "repository": self.repository,
    # #         "notes": self.notes
    # #     }

    # #     try:
    # #         # Get list of files
    # #         if os.path.isfile(self.path):
    # #             files = [self.path] if not self.path.endswith('.txt') else [
    # #                 line.strip() for line in open(self.path) 
    # #                 if line.strip() and not os.path.basename(line.strip()).startswith('.')
    # #             ]
    # #         elif os.path.isdir(self.path):
    # #             files = [
    # #                 os.path.join(root, file)
    # #                 for root, _, files in os.walk(self.path)
    # #                 for file in files
    # #                 if not file.startswith('.')
    # #             ]
    # #         else:
    # #             print(f"[ERR] Invalid path: {self.path}")
    # #             return

    # #         total_files = len(files)
    # #         print(f"Found {total_files} files to process")

    # #         with Pool(processes=max(1, multiprocessing.cpu_count() - 1)) as pool:
    # #             results = pool.map(
    # #                 process_single_file,
    # #                 [(f, i + 1, total_files, config, self.log_file) for i, f in enumerate(files)]
    # #             )

    # #         # Update statistics
    # #         for result in results:
    # #             if result is not None:
    # #                 self.total_results[result] += 1

    # #         # Generate summary
    # #         end_time = time.time()
    # #         elapsed_time = end_time - start_time
    # #         elapsed_time_pretty = time.strftime("%H:%M:%S", time.gmtime(elapsed_time))

    # #         summary = (
    # #             f"\n\nUpload finished for {self.path}"
    # #             f"\nTime required: {elapsed_time_pretty}"
    # #             f"\nResults:"
    # #             f"\n- Total processed: {sum(self.total_results.values())}"
    # #             f"\n- Successfully uploaded: {self.total_results[UploadResult.CORRECTLY]}"
    # #             f"\n- Skipped (already exists): {self.total_results[UploadResult.SKIPPED]}"
    # #             f"\n- Failed: {self.total_results[UploadResult.FAILED]}\n"
    # #         )

    # #         with open(self.log_file, "a") as f:
    # #             f.write(summary)

    # #         print(summary)

    # #     except Exception as e:
    # #         print(f"[ERR] Error in upload process: {str(e)}")

    # def upload(self):
    #     """Main upload function with multiprocessing support"""
    #     start_time = time.time()
    #     BATCH_SIZE = 1000  # Process files in batches of 1000

    #     config = {
    #         "s3_endpoint": os.getenv("S3_ENDPOINT"),
    #         "s3_access_key": os.getenv("S3_ACCESS_KEY"),
    #         "s3_secret_key": os.getenv("S3_SECRET_KEY"),
    #         "s3_bucket": os.getenv("S3_BUCKET"),
    #         "clickhouse_host": os.getenv("CLICKHOUSE_HOST"),
    #         "clickhouse_port": os.getenv("CLICKHOUSE_PORT"),
    #         "clickhouse_user": os.getenv("CLICKHOUSE_USER"),
    #         "clickhouse_password": os.getenv("CLICKHOUSE_PASSWORD"),
    #         "clickhouse_database": os.getenv("CLICKHOUSE_DATABASE"),
    #         "clickhouse_verify": os.getenv("CLICKHOUSE_ENFORCE_SSL", "False"),
    #         "repository": self.repository,
    #         "notes": self.notes
    #     }

    #     try:
    #         # Get list of files
    #         if os.path.isfile(self.path):
    #             files = [self.path] if not self.path.endswith('.txt') else [
    #                 line.strip() for line in open(self.path) 
    #                 if line.strip() and not os.path.basename(line.strip()).startswith('.')
    #             ]
    #         elif os.path.isdir(self.path):
    #             files = [
    #                 os.path.join(root, file)
    #                 for root, _, files in os.walk(self.path)
    #                 for file in files
    #                 if not file.startswith('.')
    #             ]
    #         else:
    #             print(f"[ERR] Invalid path: {self.path}")
    #             return

    #         total_files = len(files)
    #         print(f"Found {total_files} files to process")

    #         # Process files in batches
    #         for i in range(0, total_files, BATCH_SIZE):
    #             batch_files = files[i:i + BATCH_SIZE]
    #             batch_start = i + 1
    #             batch_end = min(i + BATCH_SIZE, total_files)
    #             print(f"\nProcessing batch {batch_start}-{batch_end} of {total_files}")
                
    #             with Pool(processes=max(1, multiprocessing.cpu_count() - 1)) as pool:
    #                 batch_results = pool.map(
    #                     process_single_file,
    #                     [(f, j + 1, total_files, config, self.log_file) 
    #                         for j, f in enumerate(batch_files, start=i)]
    #                 )
                    
    #                 # Update statistics for this batch
    #                 for result in batch_results:
    #                     if result is not None:
    #                         self.total_results[result] += 1

    #                 # Print intermediate summary
    #                 print(f"Batch {batch_start}-{batch_end} completed:")
    #                 print(f"- Successfully uploaded: {sum(1 for r in batch_results if r == UploadResult.CORRECTLY)}")
    #                 print(f"- Skipped (exists): {sum(1 for r in batch_results if r == UploadResult.SKIPPED)}")
    #                 print(f"- Failed: {sum(1 for r in batch_results if r == UploadResult.FAILED)}")

    #         # Generate final summary
    #         end_time = time.time()
    #         elapsed_time = end_time - start_time
    #         elapsed_time_pretty = time.strftime("%H:%M:%S", time.gmtime(elapsed_time))

    #         summary = (
    #             f"\n\nUpload finished for {self.path}"
    #             f"\nTime required: {elapsed_time_pretty}"
    #             f"\nResults:"
    #             f"\n- Total processed: {sum(self.total_results.values())}"
    #             f"\n- Successfully uploaded: {self.total_results[UploadResult.CORRECTLY]}"
    #             f"\n- Skipped (already exists): {self.total_results[UploadResult.SKIPPED]}"
    #             f"\n- Failed: {self.total_results[UploadResult.FAILED]}\n"
    #         )

    #         with open(self.log_file, "a") as f:
    #             f.write(summary)

    #         print(summary)

    #     except Exception as e:
    #         print(f"[ERR] Error in upload process: {str(e)}")

    def upload(self):
        """Main upload function with multiprocessing support"""
        start_time = time.time()
        BATCH_SIZE = 1000  # Process files in batches of 1000

        config = {
            "s3_endpoint": os.getenv("S3_ENDPOINT"),
            "s3_access_key": os.getenv("S3_ACCESS_KEY"),
            "s3_secret_key": os.getenv("S3_SECRET_KEY"),
            "s3_bucket": os.getenv("S3_BUCKET"),
            "clickhouse_host": os.getenv("CLICKHOUSE_HOST"),
            "clickhouse_port": os.getenv("CLICKHOUSE_PORT"),
            "clickhouse_user": os.getenv("CLICKHOUSE_USER"),
            "clickhouse_password": os.getenv("CLICKHOUSE_PASSWORD"),
            "clickhouse_database": os.getenv("CLICKHOUSE_DATABASE"),
            "clickhouse_verify": os.getenv("CLICKHOUSE_ENFORCE_SSL", "False"),
            "repository": self.repository,
            "notes": self.notes
        }

        try:
            # Get all existing filenames for this repository
            query = f"SELECT filename FROM samples_catalog WHERE repository = '{self.repository}'"
            # existing_files = set()
            # for row in self.ch_client.query(query).result_rows:
            #     filename = os.path.splitext(row[0])[0]  # Strip extension
            #     existing_files.add(filename)
            existing_files = set(row[0] for row in self.ch_client.query(query).result_rows)
            print(f"Found {len(existing_files)} existing files in repository")

            # Get list of files to process
            if os.path.isfile(self.path):
                files = [self.path] if not self.path.endswith('.txt') else [
                    line.strip() for line in open(self.path) 
                    if line.strip() and not os.path.basename(line.strip()).startswith('.')
                ]
            elif os.path.isdir(self.path):
                files = [
                    os.path.join(root, file)
                    for root, _, files in os.walk(self.path)
                    for file in files
                    if not file.startswith('.')
                ]
            else:
                print(f"[ERR] Invalid path: {self.path}")
                return

            # Filter out files that are already in the repository
            files_to_process = []
            for f in files:
                basename = os.path.splitext(os.path.basename(f))[0]
                if basename not in existing_files:
                    files_to_process.append(f)

            total_files = len(files_to_process)
            skipped_files = len(files) - total_files
            print(f"Found {total_files} new files to process (skipped {skipped_files} existing files)")

            if total_files == 0:
                print("No new files to process")
                return

            # Process files in batches
            for i in range(0, total_files, BATCH_SIZE):
                batch_files = files_to_process[i:i + BATCH_SIZE]
                batch_start = i + 1
                batch_end = min(i + BATCH_SIZE, total_files)
                print(f"\nProcessing batch {batch_start}-{batch_end} of {total_files}")
                
                with Pool(processes=max(1, multiprocessing.cpu_count() - 1)) as pool:
                    batch_results = pool.map(
                        process_single_file,
                        [(f, j + 1, total_files, config, self.log_file) 
                        for j, f in enumerate(batch_files, start=i)]
                    )
                    
                    # Update statistics for this batch
                    for result in batch_results:
                        if result is not None:
                            self.total_results[result] += 1

                    # Print intermediate summary
                    print(f"Batch {batch_start}-{batch_end} completed:")
                    print(f"- Successfully uploaded: {sum(1 for r in batch_results if r == UploadResult.CORRECTLY)}")
                    print(f"- Skipped (exists): {sum(1 for r in batch_results if r == UploadResult.SKIPPED)}")
                    print(f"- Failed: {sum(1 for r in batch_results if r == UploadResult.FAILED)}")

            # Generate final summary
            end_time = time.time()
            elapsed_time = end_time - start_time
            elapsed_time_pretty = time.strftime("%H:%M:%S", time.gmtime(elapsed_time))

            summary = (
                f"\n\nUpload finished for {self.path}"
                f"\nTime required: {elapsed_time_pretty}"
                f"\nResults:"
                f"\n- Files already in repository: {skipped_files}"
                f"\n- New files processed: {total_files}"
                f"\n- Successfully uploaded: {self.total_results[UploadResult.CORRECTLY]}"
                f"\n- Skipped (already exists): {self.total_results[UploadResult.SKIPPED]}"
                f"\n- Failed: {self.total_results[UploadResult.FAILED]}\n"
            )

            with open(self.log_file, "a") as f:
                f.write(summary)

            print(summary)

        except Exception as e:
            print(f"[ERR] Error in upload process: {str(e)}")
            import traceback
            print(traceback.format_exc())

if __name__ == "__main__":
    import argparse

    parser = argparse.ArgumentParser(description='Upload malware samples to S3 and catalog them.')
    parser.add_argument('path', help='Path to file or directory to process')
    parser.add_argument('repository', help='Repository name')
    parser.add_argument('--notes', help='Optional notes to add to all files', default=None)
    
    args = parser.parse_args()
    
    uploader = S3Uploader(args.path, args.repository, args.notes)
    uploader.upload()