diff --git a/lib/content_views/assigned_jobs_page.dart b/lib/content_views/assigned_jobs_page.dart index f197438..4ff6be0 100644 --- a/lib/content_views/assigned_jobs_page.dart +++ b/lib/content_views/assigned_jobs_page.dart @@ -202,8 +202,8 @@ class _AssignedJobsPageState extends State { MqttCore.instance.publishText("reaction", jsonEncode(message.toJson())); - MyApp.isarInstance.writeTxnSync(() { - MyApp.isarInstance.jobs.deleteSync(job.id); + await MyApp.isarInstance.writeTxn(() async { + await MyApp.isarInstance.jobs.delete(job.id); }); MessageService().publish(Constants.messageTopicRefreshBadges, arguments: RefreshBadgesMessage()); diff --git a/lib/content_views/main_page.dart b/lib/content_views/main_page.dart index 223d04f..1129f9e 100644 --- a/lib/content_views/main_page.dart +++ b/lib/content_views/main_page.dart @@ -381,8 +381,6 @@ class _MainPageState extends State { logoutMessage.pos!.acc = position.accuracy.toInt(); } - var json = jsonEncode(logoutMessage.toJson()); - - MqttCore.instance.publishText("session", jsonEncode(logoutMessage.toJson())); + MqttCore.instance.publishText("logout", jsonEncode(logoutMessage.toJson())); } } diff --git a/lib/content_views/messages_page.dart b/lib/content_views/messages_page.dart index 55ee6ea..1c1f0af 100644 --- a/lib/content_views/messages_page.dart +++ b/lib/content_views/messages_page.dart @@ -182,7 +182,7 @@ class _MessagesPageState extends State { const SizedBox(width: 20), Expanded( child: getDefaultButton('Ja', () async => { - await MyApp.isarInstance.writeTxnSync(() async => { await MyApp.isarInstance.messages.delete(int.parse(message.id))}), + await MyApp.isarInstance.writeTxn(() async => { await MyApp.isarInstance.messages.delete(int.parse(message.id))}), _fetchMessages(), diff --git a/lib/content_views/task_list_page.dart b/lib/content_views/task_list_page.dart index 62298c3..085ff8e 100644 --- a/lib/content_views/task_list_page.dart +++ b/lib/content_views/task_list_page.dart @@ -379,13 +379,13 @@ class _TaskListPageState extends State { }); } - void _processSignature(TaskInfo taskInfo) { + void _processSignature(TaskInfo taskInfo) async { MyApp.suppressAcceptDialog = true; SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeLeft]); - Future.delayed(const Duration(seconds: 1), () async { - showSignaturePopup(context, taskInfo, (String? signature) { + Future.delayed(const Duration(seconds: 1), () { + showSignaturePopup(context, taskInfo, (String? signature) async { MyApp.suppressAcceptDialog = false; SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); @@ -399,15 +399,15 @@ class _TaskListPageState extends State { _sendFinTourMessage(); - _finishTaskProcessing(taskInfo); + await _finishTaskProcessing(taskInfo); - MessageService().publish(Constants.messageTopicPopContentView, arguments: PopContentViewMessage(count: 2)); + MessageService().publish(Constants.messageTopicPopContentView, arguments: PopContentViewMessage(count: widget.job.state == 1 ? 2 : 3)); } }); }); } - _finishTaskProcessing(TaskInfo taskInfo) async { + Future _finishTaskProcessing(TaskInfo taskInfo) async { await MyApp.isarInstance.writeTxn(() async { await MyApp.isarInstance.taskInfos.put(taskInfo); }); @@ -444,7 +444,7 @@ class _TaskListPageState extends State { message.task.pos!.long = position.longitude; } - MqttCore.instance.publishText("job", jsonEncode(message.toJson())); + MqttCore.instance.publishText("fin_task", jsonEncode(message.toJson())); } FinTourTask _createAnswerHeader(TaskInfo taskInfo) { @@ -463,10 +463,10 @@ class _TaskListPageState extends State { return finTourTask; } - _sendFinTourMessage() async { + Future _sendFinTourMessage() async { var message = FinTour(); message.trId = widget.tour.id; - message.com = "Mir doch egal!"; + message.com = _commisionNumber; var position = MyApp.currentPosition; if (position != null) { @@ -489,8 +489,31 @@ class _TaskListPageState extends State { MqttCore.instance.publishText("fin_tour", jsonEncode(message.toJson())); widget.tour.state = Constants.stateFinishedNotConfirmed; - await MyApp.isarInstance.writeTxn(() async { + await MyApp.isarInstance.writeTxn(() async { await MyApp.isarInstance.jobs.put(widget.job); }); + + checkJobFinished(); + } + + void checkJobFinished() async { + var jobFinished = true; + + for(var tour in widget.job.tours) { + if (tour.state < 1) { + jobFinished = false; + } + } + + if (jobFinished) { + widget.job.state = 2; + for(var tour in widget.job.tours) { + tour.state = 1; + } + + await MyApp.isarInstance.writeTxn(() async { + await MyApp.isarInstance.jobs.put(widget.job); + }); + } } } diff --git a/lib/model/job.dart b/lib/model/job.dart index f5fa7b5..e7f481d 100644 --- a/lib/model/job.dart +++ b/lib/model/job.dart @@ -6,23 +6,12 @@ import 'package:stadtbote/model/tour_task.dart'; part 'job.g.dart'; -@JsonSerializable() -class JobsPayload { - List? jobs; - - JobsPayload({this.jobs}); - - factory JobsPayload.fromJson(Map json) => _$JobsPayloadFromJson(json); - - Map toJson() => _$JobsPayloadToJson(this); -} - @collection @JsonSerializable() class Job { late Id id; @JsonKey(name: 'ver') - late int ver; + late String ver; @JsonKey(name: 'state') late int state; @JsonKey(name: 'cr_filter') diff --git a/lib/model/job.g.dart b/lib/model/job.g.dart index 0279c0e..69a23cf 100644 --- a/lib/model/job.g.dart +++ b/lib/model/job.g.dart @@ -56,7 +56,7 @@ const JobSchema = CollectionSchema( r'ver': PropertySchema( id: 7, name: r'ver', - type: IsarType.long, + type: IsarType.string, ), r'vhtId': PropertySchema( id: 8, @@ -105,6 +105,7 @@ int _jobEstimateSize( bytesCount += JobTourSchema.estimateSize(value, offsets, allOffsets); } } + bytesCount += 3 + object.ver.length * 3; return bytesCount; } @@ -126,7 +127,7 @@ void _jobSerialize( JobTourSchema.serialize, object.tours, ); - writer.writeLong(offsets[7], object.ver); + writer.writeString(offsets[7], object.ver); writer.writeLong(offsets[8], object.vhtId); } @@ -151,7 +152,7 @@ Job _jobDeserialize( JobTour(), ) ?? []; - object.ver = reader.readLong(offsets[7]); + object.ver = reader.readString(offsets[7]); object.vhtId = reader.readLong(offsets[8]); return object; } @@ -184,7 +185,7 @@ P _jobDeserializeProp

( ) ?? []) as P; case 7: - return (reader.readLong(offset)) as P; + return (reader.readString(offset)) as P; case 8: return (reader.readLong(offset)) as P; default: @@ -928,46 +929,55 @@ extension JobQueryFilter on QueryBuilder { }); } - QueryBuilder verEqualTo(int value) { + QueryBuilder verEqualTo( + String value, { + bool caseSensitive = true, + }) { return QueryBuilder.apply(this, (query) { return query.addFilterCondition(FilterCondition.equalTo( property: r'ver', value: value, + caseSensitive: caseSensitive, )); }); } QueryBuilder verGreaterThan( - int value, { + String value, { bool include = false, + bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { return query.addFilterCondition(FilterCondition.greaterThan( include: include, property: r'ver', value: value, + caseSensitive: caseSensitive, )); }); } QueryBuilder verLessThan( - int value, { + String value, { bool include = false, + bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { return query.addFilterCondition(FilterCondition.lessThan( include: include, property: r'ver', value: value, + caseSensitive: caseSensitive, )); }); } QueryBuilder verBetween( - int lower, - int upper, { + String lower, + String upper, { bool includeLower = true, bool includeUpper = true, + bool caseSensitive = true, }) { return QueryBuilder.apply(this, (query) { return query.addFilterCondition(FilterCondition.between( @@ -976,6 +986,73 @@ extension JobQueryFilter on QueryBuilder { includeLower: includeLower, upper: upper, includeUpper: includeUpper, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder verStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.startsWith( + property: r'ver', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder verEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.endsWith( + property: r'ver', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder verContains(String value, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.contains( + property: r'ver', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder verMatches(String pattern, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.matches( + property: r'ver', + wildcard: pattern, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder verIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'ver', + value: '', + )); + }); + } + + QueryBuilder verIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + property: r'ver', + value: '', )); }); } @@ -1291,9 +1368,9 @@ extension JobQueryWhereDistinct on QueryBuilder { }); } - QueryBuilder distinctByVer() { + QueryBuilder distinctByVer({bool caseSensitive = true}) { return QueryBuilder.apply(this, (query) { - return query.addDistinctBy(r'ver'); + return query.addDistinctBy(r'ver', caseSensitive: caseSensitive); }); } @@ -1353,7 +1430,7 @@ extension JobQueryProperty on QueryBuilder { }); } - QueryBuilder verProperty() { + QueryBuilder verProperty() { return QueryBuilder.apply(this, (query) { return query.addPropertyName(r'ver'); }); @@ -1370,20 +1447,9 @@ extension JobQueryProperty on QueryBuilder { // JsonSerializableGenerator // ************************************************************************** -JobsPayload _$JobsPayloadFromJson(Map json) => JobsPayload( - jobs: (json['jobs'] as List?) - ?.map((e) => Job.fromJson(e as Map)) - .toList(), - ); - -Map _$JobsPayloadToJson(JobsPayload instance) => - { - 'jobs': instance.jobs, - }; - Job _$JobFromJson(Map json) => Job() ..id = json['id'] as int - ..ver = json['ver'] as int + ..ver = json['ver'] as String ..state = json['state'] as int ..crFilter = json['cr_filter'] as String? ..ordertime = json['ordertime'] as String diff --git a/lib/popups/accept_jobs_popup.dart b/lib/popups/accept_jobs_popup.dart index 019830f..85244ad 100644 --- a/lib/popups/accept_jobs_popup.dart +++ b/lib/popups/accept_jobs_popup.dart @@ -203,7 +203,7 @@ Future showAcceptJobsPopup(BuildContext context, List jobs, Function( }); } -_sendAnswer(Job job, int item) { +_sendAnswer(Job job, int item) async { var currentPosition = MyApp.currentPosition; var message = Reaction(); @@ -219,8 +219,8 @@ _sendAnswer(Job job, int item) { MqttCore.instance.publishText("reaction", jsonEncode(message.toJson())); - MyApp.isarInstance.writeTxnSync(() { - MyApp.isarInstance.jobs.deleteSync(job.id); + await MyApp.isarInstance.writeTxn(() async{ + await MyApp.isarInstance.jobs.delete(job.id); }); MessageService().publish(Constants.messageTopicRefreshBadges, arguments: RefreshBadgesMessage()); diff --git a/lib/protocoll_messages/acknowledge_job.dart b/lib/protocoll_messages/acknowledge_job.dart index a1502f3..18f4cfd 100644 --- a/lib/protocoll_messages/acknowledge_job.dart +++ b/lib/protocoll_messages/acknowledge_job.dart @@ -19,7 +19,7 @@ class AcknowledgeJobReceived { late int state; - late int ver; + late String ver; late int utc; diff --git a/lib/protocoll_messages/acknowledge_job.g.dart b/lib/protocoll_messages/acknowledge_job.g.dart index 697f489..165d1d5 100644 --- a/lib/protocoll_messages/acknowledge_job.g.dart +++ b/lib/protocoll_messages/acknowledge_job.g.dart @@ -21,7 +21,7 @@ AcknowledgeJobReceived _$AcknowledgeJobReceivedFromJson( AcknowledgeJobReceived() ..id = json['id'] as int ..state = json['state'] as int - ..ver = json['ver'] as int + ..ver = json['ver'] as String ..utc = json['utc'] as int; Map _$AcknowledgeJobReceivedToJson( diff --git a/lib/tools/mqtt_core.dart b/lib/tools/mqtt_core.dart index 46302ff..9d7a92f 100644 --- a/lib/tools/mqtt_core.dart +++ b/lib/tools/mqtt_core.dart @@ -4,11 +4,14 @@ import 'dart:math'; import 'package:archive/archive.dart'; import 'package:device_info_plus/device_info_plus.dart'; +import 'package:http/http.dart' as http; import 'package:isar/isar.dart'; import 'package:mqtt_client/mqtt_client.dart'; import 'package:mqtt_client/mqtt_server_client.dart'; import 'package:stadtbote/model/enqueued_message.dart'; +import 'package:stadtbote/model/job.dart'; import 'package:stadtbote/model/log_entry.dart'; +import 'package:stadtbote/model/message.dart'; import 'package:stadtbote/model/status.dart'; import 'package:stadtbote/protocoll_messages/acknowledge_job.dart'; import 'package:stadtbote/protocoll_messages/bootstrap_request.dart'; @@ -16,9 +19,6 @@ import 'package:stadtbote/protocoll_messages/bootstrap_response_payload.dart'; import 'package:stadtbote/protocoll_messages/device_log_request.dart'; import 'package:stadtbote/protocoll_messages/device_log_response.dart'; import 'package:stadtbote/protocoll_messages/device_object.dart'; -import 'package:stadtbote/model/job.dart'; -import 'package:stadtbote/model/message.dart'; -import 'package:stadtbote/protocoll_messages/payload_container.dart'; import 'package:stadtbote/protocoll_messages/start_session_message.dart'; import 'package:stadtbote/protocoll_messages/sync_jobs_message.dart'; import 'package:stadtbote/protocoll_messages/track_message.dart'; @@ -31,8 +31,6 @@ import 'package:stadtbote/tools/messages/session_info_update.dart'; import 'package:stadtbote/tools/messages/status_info_update.dart'; // ignore: depend_on_referenced_packages import 'package:typed_data/typed_buffers.dart'; -import 'package:http/http.dart' as http; -import 'package:uuid/uuid.dart'; import '../main.dart'; import '../model/session_status.dart'; @@ -52,6 +50,7 @@ class MqttCore { late bool _disconnectInProgress = false; late String _brokerUri; + late String _clientId; late int _brokerPort; late String _fromServerTopic; late String _toServerTopic; @@ -101,8 +100,8 @@ class MqttCore { _mqttClient.connectionMessage = MqttConnectMessage() .withClientIdentifier(await Util.getAppUuid()) .withWillQos(MqttQos.atMostOnce) - .withWillTopic('willTopic') - .withWillMessage('willMessage') + //.withWillTopic('willTopic') + //.withWillMessage('willMessage') .authenticateAs("app", "apppwd"); await _mqttClient.connect(); @@ -145,83 +144,65 @@ class MqttCore { var buffer = Uint8Buffer(); buffer.addAll(utf8.encode(text)); - _mqttClient.publishMessage(topic, MqttQos.exactlyOnce, buffer); + var fullTopic = "$_toServerTopic$topic/$_clientId"; - Util.logInfo("message\n$text\nsend to $topic"); - } + _mqttClient.publishMessage(fullTopic, MqttQos.exactlyOnce, buffer); - publishPayloadMessage(String topic, Map payload) { - var payloadContainer = PayloadContainer(); - payloadContainer.id = const Uuid().v4().toString(); - payloadContainer.recv = topic; - payloadContainer.store = true; - payloadContainer.payload = payload; - - var json = jsonEncode(payloadContainer.toJson()); - - try { - publishText(_toServerTopic, json); - } catch (e) { - _enqueueMessage(_toServerTopic, jsonEncode(payloadContainer.toJson())); - } + Util.logInfo("message\n$text\nsend to $fullTopic"); } void _setupSubscriptions() async { Util.logInfo('_setupSubscriptions called'); - _mqttClient.updates?.listen((List> c) { + _mqttClient.updates?.listen((List> messages) { try { - final MqttPublishMessage message = c[0].payload as MqttPublishMessage; - String payload = utf8.decode(MqttPublishPayload.bytesToStringAsString(message.payload.message).codeUnits); - var topic = message.variableHeader?.topicName; + for (var mqttMessage in messages) { + final MqttPublishMessage message = mqttMessage.payload as MqttPublishMessage; - Util.logInfo('message received\ntopic: $topic\nmessage: $payload'); + if (message.variableHeader!.topicName.endsWith(_clientId)) { + String payload = utf8.decode(MqttPublishPayload.bytesToStringAsString(message.payload.message).codeUnits); + var topicArray = message.variableHeader?.topicName; + var topicArraySplited = topicArray!.split("/"); + var topic = topicArraySplited[3]; - Map messageData = jsonDecode(payload); + Util.logInfo('message received\ntopic: $topic\nmessage: $payload'); - for (var entry in messageData.keys) { - if (entry == 'payload') { - var payload = messageData[entry]; - for (var payloadEntry in payload.keys) { - var payloadData = payload[payloadEntry]; + switch(topic) { + case 'session': + _sessionMessageReceived(jsonDecode(payload)); + break; - switch(payloadEntry) { - case 'session': - _sessionMessageReceived(payloadData); - break; + case 'status': + _statusMessageReceived(jsonDecode(payload)); + break; - case 'status': - _statusMessageReceived(payloadData); - break; + case 'ranks': + //_rankingMessageReceived(messageData); + break; - case 'ranks': - _rankingMessageReceived(payloadData); - break; + case 'job': + _jobMessageReceived(jsonDecode(payload)); + break; - case 'jobs': - _jobMessageReceived(payloadData); - break; + case 'job_del': + _jobDeleteReceived(jsonDecode(payload)); + break; - case 'job_del': - _jobDeleteReceived(payloadData); - break; + case 'sync_request': + _syncRequestReceived(jsonDecode(payload)); + break; - case 'sync_request': - _syncRequestReceived(payloadData); - break; + case "mssg": + _messageMessageReceived(jsonDecode(payload)); + break; - case "mssg": - _messageMessageReceived(payloadData); - break; + case "upload_device_log": + _messageUploadDeviceLogReceived(jsonDecode(payload)); + break; - case "upload_device_log": - _messageUploadDeviceLogReceived(payloadData); - break; - - default: - Util.logInfo('Unknown topic: $payloadEntry'); - break; - } + default: + Util.logInfo('Unknown topic: $topic'); + break; } } } @@ -230,8 +211,9 @@ class MqttCore { } }); - _mqttClient.subscribe(_fromServerTopic, MqttQos.exactlyOnce); - Util.logInfo('subscribed to topic: $_fromServerTopic'); + var fromServerTopic = "$_fromServerTopic#"; + _mqttClient.subscribe(fromServerTopic, MqttQos.exactlyOnce); + Util.logInfo('subscribed to topic: $fromServerTopic'); MessageService().publish(Constants.messageTopicConnectionStatusChanged, arguments: ConnectionStatus(status: ConnectionStatusEnum.connected)); } @@ -243,7 +225,7 @@ class MqttCore { await _sendEnqueuedMessages(); - var sessionStatusMessage = SessionStatus.fromJson(payloadData['status']); + var sessionStatusMessage = SessionStatus.fromJson(payloadData); await MyApp.isarInstance.writeTxn(() async { await MyApp.isarInstance.sessionStatus.clear(); @@ -279,28 +261,26 @@ class MqttCore { } void _jobMessageReceived(payloadData) async { - for (var foundJobData in payloadData) { - Job newJob = Job.fromJson(foundJobData); + Job newJob = Job.fromJson(payloadData); - await MyApp.isarInstance.writeTxn(() async { - await MyApp.isarInstance.jobs.put(newJob); - }); + await MyApp.isarInstance.writeTxn(() async { + await MyApp.isarInstance.jobs.put(newJob); + }); - if (newJob.state == Constants.stateAssigned) { - if (newJob.global) { - await Util.playMp3('aaa.mp3'); - } else { - await Util.playMp3('job_received.mp3'); - } + if (newJob.state == Constants.stateAssigned) { + if (newJob.global) { + await Util.playMp3('aaa.mp3'); + } else { + await Util.playMp3('job_received.mp3'); } + } - try { - MessageService().publish(Constants.messageTopicJobReceived, arguments: JobReceivedMessage(job: newJob)); - } catch (ex) { - Util.logException("publish messageTopicJobReceived failed!"); - } + _acknowlegdeJob(newJob); - _acknowlegdeJob(newJob); + try { + MessageService().publish(Constants.messageTopicJobReceived, arguments: JobReceivedMessage(job: newJob)); + } catch (ex) { + Util.logException("publish messageTopicJobReceived failed!"); } } @@ -402,18 +382,19 @@ class MqttCore { handshakeMessage.ver = await Util.getAppVersion(); var jsonMap = handshakeMessage.toJson(); - var json = jsonEncode(jsonMap); - var uri = "http://test-app-server.dns.army:8080=$json"; + var json = Uri.encodeFull(jsonEncode(jsonMap)); + var uri = "http://test-app-server.dns.army:8080/bootstrap?json=$json"; Util.logInfo("Bootstrap request: $uri"); var response = await http.get(Uri.parse(uri)); var responseText = response.body; - var bootstrapResponsePayload = BootstrapResponse.fromJson(jsonDecode(responseText)["payload"]); + var bootstrapResponsePayload = BootstrapResponse.fromJson(jsonDecode(responseText)); var brokerUriAndPortArray = bootstrapResponsePayload.broker.replaceFirst("mqtt://", "").split(":"); _brokerUri = brokerUriAndPortArray[0]; _brokerPort = int.parse(brokerUriAndPortArray[1]); + _clientId = bootstrapResponsePayload.id; _fromServerTopic = bootstrapResponsePayload.fromServer; _toServerTopic = bootstrapResponsePayload.toServer; @@ -446,7 +427,7 @@ class MqttCore { answer.sync.jobs.add(syncJob); } - MqttCore.instance.publishPayloadMessage("server", answer.toJson()); + MqttCore.instance.publishText("sync_request_response", jsonEncode(answer.toJson())); } void _startTrackTimer() { @@ -460,7 +441,7 @@ class MqttCore { trackMessage.pos!.long = position.longitude; trackMessage.pos!.acc = position.accuracy.toInt(); - publishPayloadMessage("track", trackMessage.toJson()); + publishText("track", jsonEncode(trackMessage.toJson())); } }); } @@ -507,6 +488,6 @@ class MqttCore { message.received.ver = job.ver; message.received.utc = DateTime.now().millisecondsSinceEpoch; - MqttCore.instance.publishPayloadMessage('job', message.toJson()); + MqttCore.instance.publishText('job', jsonEncode(message.toJson())); } }