Skip to content

Commit 437f935

Browse files
feat: udp/tcp stuff
1 parent 08c795c commit 437f935

File tree

5 files changed

+260
-59
lines changed

5 files changed

+260
-59
lines changed

lib/bloc/process_bloc/process_bloc.dart

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -54,20 +54,50 @@ class ProcessBloc extends Bloc<ProcessEvent, ProcessState> {
5454
queue: state.queue.skip(1).toList(),
5555
progress: '0',
5656
);
57-
unawaited(_extractor
58-
.extractFile(
59-
file,
60-
listenProgress: (progress) => add(ProcessFileExtractorProgress(progress)),
61-
listenOutput: (line) => add(ProcessFileExtractorOutput(line)),
62-
listenVideoDetails: (videoDetails) =>
63-
add(ProcessFileVideoDetails(videoDetails)),
64-
)
65-
.then((value) {
66-
if (value != 0) {
67-
add(ProcessError(value));
68-
}
69-
add(ProcessFileComplete(file));
70-
}));
57+
unawaited(
58+
_extractor
59+
.extractFile(
60+
file,
61+
listenProgress: (progress) =>
62+
add(ProcessFileExtractorProgress(progress)),
63+
listenOutput: (line) => add(ProcessFileExtractorOutput(line)),
64+
listenVideoDetails: (videoDetails) =>
65+
add(ProcessFileVideoDetails(videoDetails)),
66+
)
67+
.then(
68+
(value) {
69+
if (value != 0) {
70+
add(ProcessError(value));
71+
}
72+
add(ProcessFileComplete(file));
73+
},
74+
),
75+
);
76+
}
77+
78+
Stream<ProcessState> _extractOnNetwork(
79+
String type, String location, String tcppassword, String tcpdesc) async* {
80+
unawaited(
81+
_extractor
82+
.extractFileOverNetwork(
83+
type: type,
84+
location: location,
85+
tcpdesc: tcpdesc,
86+
tcppasswrd: tcppassword,
87+
listenProgress: (progress) =>
88+
add(ProcessFileExtractorProgress(progress)),
89+
listenOutput: (line) => add(ProcessFileExtractorOutput(line)),
90+
listenVideoDetails: (videoDetails) =>
91+
add(ProcessFileVideoDetails(videoDetails)),
92+
)
93+
.then(
94+
(value) {
95+
if (value != 0) {
96+
add(ProcessError(value));
97+
}
98+
},
99+
),
100+
);
71101
}
72102

73103
@override
@@ -170,6 +200,9 @@ class ProcessBloc extends Bloc<ProcessEvent, ProcessState> {
170200
);
171201
} else if (event is ProcessError) {
172202
yield state.copyWith(current: state.current, exitCode: event.exitCode);
203+
} else if (event is ProcessOnNetwork) {
204+
yield* _extractOnNetwork(
205+
event.type, event.location, event.tcppassword, event.tcpdesc);
173206
}
174207
}
175208
}

lib/bloc/process_bloc/process_event.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,17 @@ class ProcessError extends ProcessEvent {
6060
const ProcessError(this.exitCode);
6161
}
6262

63+
class ProcessOnNetwork extends ProcessEvent {
64+
final String type;
65+
final String location;
66+
final String tcppassword;
67+
final String tcpdesc;
68+
69+
ProcessOnNetwork(
70+
{required this.type,
71+
required this.location,
72+
required this.tcppassword,
73+
required this.tcpdesc});
74+
}
75+
6376
class GetCCExtractorVersion extends ProcessEvent {}

lib/repositories/ccextractor.dart

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import 'package:file_selector/file_selector.dart';
66
import 'package:ccxgui/models/settings_model.dart';
77
import 'package:ccxgui/repositories/settings_repository.dart';
88

9+
enum NETWORK_TYPE { udp, tcp }
10+
911
class CCExtractor {
1012
late Process process;
1113
final RegExp progressRegx = RegExp(r'###PROGRESS#(\d+)', multiLine: true);
@@ -39,11 +41,63 @@ class CCExtractor {
3941
);
4042

4143
process.stdout.transform(latin1.decoder).listen((update) {
42-
//print(update);
44+
print(update);
45+
});
46+
47+
process.stderr.transform(latin1.decoder).listen((update) {
48+
print(update);
49+
if (progressRegx.hasMatch(update)) {
50+
for (RegExpMatch i in progressRegx.allMatches(update)) {
51+
listenProgress(i[1]!);
52+
}
53+
}
54+
if (logsRegx.hasMatch(update)) {
55+
for (RegExpMatch i in logsRegx.allMatches(update)) {
56+
// 1,2 are here for regex groups, 1 corresponds to subtitle regex
57+
// match and 2 is time regex match. Later we can seperate this if
58+
// needed (no additonal benefit rn imo;td)
59+
if (i[1] != null) listenOutput(i[1]!);
60+
if (i[2] != null) listenOutput(i[2]!);
61+
}
62+
}
63+
if (videoDetailsRegx.hasMatch(update)) {
64+
for (RegExpMatch i in videoDetailsRegx.allMatches(update)) {
65+
listenVideoDetails(i[1]!.split('#'));
66+
}
67+
}
68+
});
69+
return process.exitCode;
70+
}
71+
72+
Future<int> extractFileOverNetwork({
73+
required String type,
74+
required String location,
75+
required String tcppasswrd,
76+
required String tcpdesc,
77+
required Function(String) listenProgress,
78+
required Function(String) listenOutput,
79+
required Function(List<String>) listenVideoDetails,
80+
}) async {
81+
settings = await settingsRepository.getSettings();
82+
List<String> paramsList = settingsRepository.getParamsList(settings);
83+
process = await Process.start(
84+
ccextractor,
85+
[
86+
'-' + type,
87+
location,
88+
tcppasswrd.isNotEmpty ? '-' + tcppasswrd : '',
89+
tcpdesc.isNotEmpty ? '-' + tcpdesc : '',
90+
'--gui_mode_reports',
91+
...paramsList,
92+
],
93+
);
94+
95+
process.stdout.transform(latin1.decoder).listen((update) {
96+
print(update);
4397
});
4498

4599
process.stderr.transform(latin1.decoder).listen((update) {
46-
// print(update);
100+
print(update);
47101
if (progressRegx.hasMatch(update)) {
48102
for (RegExpMatch i in progressRegx.allMatches(update)) {
49103
listenProgress(i[1]!);

lib/screens/dashboard/components/udp_button.dart

Lines changed: 138 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,40 @@
1+
import 'package:ccxgui/bloc/process_bloc/process_bloc.dart';
2+
import 'package:ccxgui/utils/constants.dart';
13
import 'package:flutter/material.dart';
4+
import 'package:flutter/services.dart';
5+
import 'package:flutter_bloc/flutter_bloc.dart';
26

3-
import 'package:ccxgui/utils/constants.dart';
7+
class ListenOnUDPButton extends StatefulWidget {
8+
@override
9+
_ListenOnUDPButtonState createState() => _ListenOnUDPButtonState();
10+
}
11+
12+
class _ListenOnUDPButtonState extends State<ListenOnUDPButton> {
13+
final List<DropdownMenuItem<String>> networkTypes = [
14+
DropdownMenuItem(
15+
value: 'udp',
16+
child: Text('udp'),
17+
),
18+
DropdownMenuItem(
19+
value: 'tcp',
20+
child: Text('tcp'),
21+
),
22+
];
23+
String type = 'udp';
24+
final TextEditingController hostController =
25+
TextEditingController(text: '127.0.0.1');
26+
final TextEditingController portController = TextEditingController();
27+
final TextEditingController passwordController = TextEditingController();
28+
final TextEditingController descController = TextEditingController();
429

5-
class ListenOnUDPButton extends StatelessWidget {
30+
String get compileLocationString {
31+
String _host =
32+
hostController.text.isNotEmpty ? hostController.text + ':' : '';
33+
return _host + portController.text;
34+
}
35+
36+
bool _validatePort = false;
37+
final _formKey = GlobalKey<FormState>();
638
@override
739
Widget build(BuildContext context) {
840
return Padding(
@@ -14,43 +46,118 @@ class ListenOnUDPButton extends StatelessWidget {
1446
builder: (context) {
1547
return AlertDialog(
1648
title: Text(
17-
'Read the input via UDP (listening in the specified port)'),
18-
content: Column(
19-
mainAxisSize: MainAxisSize.min,
20-
crossAxisAlignment: CrossAxisAlignment.start,
21-
children: [
22-
Padding(
23-
padding: const EdgeInsets.all(8.0),
24-
child: TextFormField(
25-
initialValue: '127.0.0.1',
26-
decoration: InputDecoration(
27-
hintText: 'Enter host here',
28-
labelText: 'Host: ',
29-
labelStyle: TextStyle(fontSize: 18),
30-
hintStyle: TextStyle(height: 2),
31-
),
32-
),
33-
),
34-
Padding(
49+
'Read the input on network (listening in the specified port)'),
50+
content: StatefulBuilder(
51+
builder: (BuildContext context, StateSetter setState) {
52+
return Padding(
3553
padding: const EdgeInsets.all(8.0),
36-
child: TextFormField(
37-
autofocus: true,
38-
decoration: InputDecoration(
39-
hintText: 'Enter port here',
40-
labelText: 'Port: ',
41-
labelStyle: TextStyle(fontSize: 18),
42-
hintStyle: TextStyle(height: 2),
54+
child: Form(
55+
key: _formKey,
56+
child: Column(
57+
mainAxisSize: MainAxisSize.min,
58+
crossAxisAlignment: CrossAxisAlignment.start,
59+
children: [
60+
DropdownButton<String>(
61+
items: networkTypes,
62+
isExpanded: true,
63+
value: type,
64+
onChanged: (String? newValue) {
65+
setState(() {
66+
type = newValue!;
67+
});
68+
},
69+
),
70+
TextFormField(
71+
controller: hostController,
72+
decoration: InputDecoration(
73+
hintText: 'Enter host here',
74+
labelText: 'Host: ',
75+
labelStyle: TextStyle(fontSize: 16),
76+
hintStyle: TextStyle(height: 2),
77+
),
78+
),
79+
TextFormField(
80+
controller: portController,
81+
inputFormatters: [
82+
FilteringTextInputFormatter.allow(
83+
RegExp(r'^\d+(\.\d+)*$'),
84+
),
85+
],
86+
autofocus: true,
87+
validator: (text) {
88+
if (text == null || text.isEmpty) {
89+
return 'Port cannot be empty';
90+
}
91+
return null;
92+
},
93+
decoration: InputDecoration(
94+
hintText: 'Enter port here',
95+
labelText: 'Port: ',
96+
labelStyle: TextStyle(fontSize: 16),
97+
hintStyle: TextStyle(height: 2),
98+
),
99+
),
100+
if (type == 'tcp')
101+
TextFormField(
102+
controller: passwordController,
103+
decoration: InputDecoration(
104+
hintText:
105+
'Server password for new connections to tcp server',
106+
labelText: 'TCP password: ',
107+
labelStyle: TextStyle(fontSize: 16),
108+
hintStyle: TextStyle(height: 2),
109+
),
110+
),
111+
if (type == 'tcp')
112+
TextFormField(
113+
controller: descController,
114+
decoration: InputDecoration(
115+
hintText:
116+
'Sends to the server short description about captiobs',
117+
labelText: 'TCP description: ',
118+
labelStyle: TextStyle(fontSize: 16),
119+
hintStyle: TextStyle(height: 2),
120+
),
121+
),
122+
],
43123
),
44124
),
45-
),
46-
],
125+
);
126+
},
47127
),
48128
actions: [
129+
Padding(
130+
padding: const EdgeInsets.only(bottom: 16),
131+
child: MaterialButton(
132+
onPressed: () {
133+
Navigator.pop(context);
134+
},
135+
child: Text(
136+
'Cancel',
137+
style: TextStyle(fontSize: 15),
138+
),
139+
),
140+
),
49141
Padding(
50142
padding: const EdgeInsets.only(bottom: 16, right: 12),
51143
child: MaterialButton(
52-
onPressed: () => Navigator.pop(context),
53-
child: Text('Start'),
144+
onPressed: () {
145+
if (_formKey.currentState!.validate()) {
146+
context.read<ProcessBloc>().add(
147+
ProcessOnNetwork(
148+
type: type,
149+
location: compileLocationString,
150+
tcpdesc: descController.text,
151+
tcppassword: passwordController.text,
152+
),
153+
);
154+
Navigator.pop(context);
155+
}
156+
},
157+
child: Text(
158+
'Start',
159+
style: TextStyle(fontSize: 15),
160+
),
54161
),
55162
),
56163
],

lib/screens/dashboard/dashboard.dart

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,12 @@ class ClearFilesButton extends StatelessWidget {
5252
@override
5353
Widget build(BuildContext context) {
5454
return BlocConsumer<ProcessBloc, ProcessState>(
55-
listenWhen: (previous, current) {
56-
return previous.exitCode != current.exitCode;
57-
},
5855
listener: (context, processState) {
59-
CustomSnackBarMessage.show(
60-
context, CCExtractor.exitCodes[processState.exitCode]!);
56+
//TODO: fix only works the first time, bloc wont emit same state
57+
if (CCExtractor.exitCodes[processState.exitCode] != null) {
58+
CustomSnackBarMessage.show(
59+
context, CCExtractor.exitCodes[processState.exitCode]!);
60+
}
6161
},
6262
builder: (context, processState) {
6363
return BlocBuilder<DashboardBloc, DashboardState>(
@@ -314,13 +314,7 @@ class LogsContainer extends StatelessWidget {
314314
'Framerate: ${state.videoDetails.isNotEmpty ? state.videoDetails[3].substring(5) : ''}',
315315
style: TextStyle(fontSize: 15),
316316
),
317-
// Padding(
318-
// padding: const EdgeInsets.only(right: 10.0),
319-
// child: Text(
320-
// 'Encoding: ${state.videoDetails[3]}',
321-
// style: TextStyle(fontSize: 15),
322-
// ),
323-
// ),
317+
324318
],
325319
),
326320
),

0 commit comments

Comments
 (0)