src/Controller/Api/IbeaconLastSeenController.php line 191

Open in your IDE?
  1. <?php
  2. namespace App\Controller\Api;
  3. use App\Entity\ApiCallLog;
  4. use App\Entity\IbeaconUpdateApiCallLog;
  5. use App\Entity\IbeaconLastSeen;
  6. use App\Entity\IbeaconLastSeenHistory;
  7. use App\Entity\IbeaconLowBatteryAlert;
  8. use App\Entity\Patient;
  9. use App\Entity\PatientIbeacon;
  10. use App\Entity\Ibeacon;
  11. use App\Entity\User;
  12. use App\LocationReader;
  13. use App\SocketConnection;
  14. use Doctrine\ORM\Query\Expr\Join;
  15. use Symfony\Bundle\FrameworkBundle\Controller\Controller;
  16. use Symfony\Component\HttpKernel\Exception\HttpException;
  17. use Symfony\Component\HttpFoundation\JsonResponse;
  18. use Symfony\Component\HttpFoundation\Request;
  19. use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
  20. use Symfony\Component\Routing\Annotation\Route;
  21. use Symfony\Component\Serializer\SerializerInterface;
  22. use Symfony\Component\Stopwatch\Stopwatch;
  23. use Symfony\Component\HttpClient\HttpClient;
  24. /**
  25.  * @Route("/ibeacons")
  26.  */
  27. class IbeaconLastSeenController extends Controller
  28. {
  29.     /**
  30.      * @var SerializerInterface
  31.      */
  32.     private $serializer;
  33.     private $socketConnection;
  34.     private $locationReader;
  35.     private $ibeaconUpdateDistanceThreshold;
  36.     private $stopwatch;
  37.     public function __construct(
  38.         SerializerInterface $serializer,
  39.         SocketConnection $socketConnection,
  40.         LocationReader $locationReader,
  41.         $ibeaconUpdateDistanceThreshold
  42.     ) {
  43.         $this->serializer $serializer;
  44.         $this->socketConnection $socketConnection;
  45.         $this->locationReader $locationReader;
  46.         $this->ibeaconUpdateDistanceThreshold $ibeaconUpdateDistanceThreshold;
  47.         $this->stopwatch = new Stopwatch();
  48.     }
  49.     /**
  50.      * @Route("/package", methods={"POST"})
  51.      */
  52.     public function package(Request $request)
  53.     {
  54.         $packages json_decode($request->getContent(), true);
  55.         $ibeaconResults = [];
  56.         $lost false;
  57.         foreach ($packages as $key => $value) {
  58.             $ibeaconResults[$key] = $this->getDoctrine()->getRepository(PatientIbeacon::class)->findOneBy(['mac' => $value['tmac']]);
  59.         }
  60.         foreach ($ibeaconResults as $key => $ibeacon) {
  61.             $packages[$key]['lost'] = 0;
  62.             if (!$ibeacon) {
  63.                 unset($packages[$key]);
  64.             } else {
  65.                 if ($ibeacon->getPatient() && $ibeacon->getPatient()->getPatientStatus() == Patient::STATUS_LOST) {
  66.                     $lost true;
  67.                     $packages[$key]['lost'] = 1;
  68.                 }
  69.                 if (!$ibeacon->getLastSeen()) {
  70.                     $lastSeen = new IbeaconLastSeen();
  71.                     $lastSeen->setIbeacon($ibeacon);
  72.                     $this->getDoctrine()->getManager()->persist($lastSeen);
  73.                     $this->getDoctrine()->getManager()->flush();
  74.                 }
  75.                 if (isset($packages[$key]['battery']) && $packages[$key]['battery']) {
  76.                     $ibeacon->setBattery($packages[$key]['battery']);
  77.                     $ibeacon->setUpdatedAt(new \DateTime('now'));
  78.                     $this->getDoctrine()->getManager()->persist($ibeacon);
  79.                     $this->getDoctrine()->getManager()->flush();
  80.                     unset($packages[$key]['battery']);
  81.                 }
  82.             }
  83.         }
  84.         $packages array_values($packages);
  85.         if (count($packages)) {
  86.             $dataInJson json_encode($packages);
  87.             $dataToSend strlen($dataInJson) . $dataInJson;
  88.             $this->stopwatch->start('uploadData');
  89.             $this->socketConnection->write($dataToSend);
  90.             $uploadDataEvent $this->stopwatch->stop('uploadData');
  91.             $uploadDataEvent->ensureStopped();
  92.             if ($uploadDataEvent->getDuration() >= 2100) {
  93.                 $log = new ApiCallLog();
  94.                 $log->setDuration($uploadDataEvent->getDuration() / 1000.0);
  95.                 $log->setType("POST");
  96.                 $log->setSessionId(uniqid());
  97.                 $this->getDoctrine()->getManager()->persist($log);
  98.                 $this->getDoctrine()->getManager()->flush();
  99.             }
  100.         }
  101.         return new JsonResponse(array("lost" => $lost), 200);
  102.     }
  103.     /**
  104.      * @Route("/uptime", methods={"POST"})
  105.      */
  106.     public function uptime(Request $request)
  107.     {
  108.         $uptime json_decode($request->getContent(), true);
  109.         if (isset($uptime[0]) && (isset($uptime[0]['type']) && $uptime[0]['type'] == 3) && isset($uptime[0]['uptime'])) {
  110.             $dataInJson json_encode($uptime);
  111.             $dataToSend strlen($dataInJson) . $dataInJson;
  112.             $this->stopwatch->start('uploadUptime');
  113.             $this->socketConnection->write($dataToSend);
  114.             $uploadDataEvent $this->stopwatch->stop('uploadUptime');
  115.             $uploadDataEvent->ensureStopped();
  116.             if ($uploadDataEvent->getDuration() >= 2100) {
  117.                 $log = new ApiCallLog();
  118.                 $log->setDuration($uploadDataEvent->getDuration() / 1000.0);
  119.                 $log->setType("POST");
  120.                 $log->setSessionId(uniqid());
  121.                 $this->getDoctrine()->getManager()->persist($log);
  122.                 $this->getDoctrine()->getManager()->flush();
  123.             }
  124.             return new JsonResponse(array(), 200);
  125.         } else {
  126.             return new JsonResponse(array("error" => "Incorrect data format"), 402);
  127.         }
  128.     }
  129.     /**
  130.      *
  131.      * @Route("/match", methods={"POST"})
  132.      */
  133.     public function match(Request $request)
  134.     {
  135.         $packages json_decode($request->getContent(), true);
  136.         $ibeaconResults = [];
  137.         $data "[";
  138.         foreach ($packages as $key => $value) {
  139.             $ibeaconResults[$key] = $this->getDoctrine()->getRepository(Ibeacon::class)->findOneBy(['major' => $value['major'], 'minor' => $value['minor']]);
  140.         }
  141.         foreach ($ibeaconResults as $key => $value) {
  142.             if (!$value) {
  143.                 unset($packages[$key]);
  144.             } else {
  145.                 $mac $value->getMajor() . $value->getMinor();
  146.                 $patientIbeaconResults $this->getDoctrine()->getRepository(PatientIbeacon::class)->findOneBy(['mac' => $mac]);
  147.                 $data .= ($data == "[" "" ",") . $this->serializer->serialize([
  148.                         'mac' => $mac,
  149.                         'ibeaconName' => $value->getName(),
  150.                         'patientIbeaconId' => $patientIbeaconResults $patientIbeaconResults->getId() : "",
  151.                         'patientId' => $patientIbeaconResults $patientIbeaconResults->getPatient()->getId() : "",
  152.                         'patientName' => $patientIbeaconResults $patientIbeaconResults->getPatient()->getName() : "",
  153.                     ], 'json');
  154.             }
  155.         }
  156.         $data .= "]";
  157.         return new JsonResponse($data200, [], true);
  158.     }
  159.     /**
  160.      *
  161.      * @Route("/update", methods={"POST"})
  162.      */
  163.     public function update(Request $request)
  164.     {
  165.         $decoded base64_decode($request->getContent());
  166.         $packages json_decode($decodedtrue);
  167.         $sessionId uniqid();
  168.         $data "";
  169.         for ($i 0$i count($packages); $i++) {
  170.             $ibeacons[$i] = $this->getDoctrine()->getRepository(PatientIbeacon::class)->findOneBy(['mac' => $packages[$i]['tmac']]);
  171.             if ($ibeacons[$i]) {
  172.                 $executionTime $this->updateAPILastSeen($ibeacons[$i], $packages[$i], $sessionId);
  173.                 foreach ($executionTime as $key => $value) {
  174.                     if ($value >= 2.1) {
  175.                         $logGet = new ApiCallLog();
  176.                         $logGet->setDuration($value);
  177.                         $logGet->setType($key);
  178.                         $logGet->setSessionId($sessionId);
  179.                         $this->getDoctrine()->getManager()->persist($logGet);
  180.                         $this->getDoctrine()->getManager()->flush();
  181.                     }
  182.                 }
  183.                 $updatedIbeacon $this->getDoctrine()->getRepository(PatientIbeacon::class)->findOneBy(['mac' => $packages[$i]['tmac']]);
  184.                 $this->updateRoute($updatedIbeacon);
  185.                 $data .= ($data == "" "" ",") . $this->serializer->serialize([
  186.                         'id' => $ibeacons[$i]->getId(),
  187.                     ], 'json');
  188.             }
  189.         }
  190.         return new JsonResponse("success"200, [], true);
  191.     }
  192.     public function updateAPILastSeen($ibeacon$data$sessionId)
  193.     {
  194.         $executionTime = [];
  195.         $lastSeen null;
  196.         if ($data) {
  197.             $ibeaconUpdateLog = new IbeaconUpdateApiCallLog();
  198.             $ibeaconUpdateLog->setSessionId($sessionId);
  199.             $ibeaconUpdateLog->setIbeacon($ibeacon);
  200.             $lat $data['lat'];
  201.             $long $data['long'];
  202.             $resultLastSeen round($data['ts']);
  203.             $gpsacc = (isset($data['gpsacc']) ? (int)$data['gpsacc'] : 0);
  204.             $signal = ($data['signal'] ?? 'BLE');
  205.             $lastLocation = [
  206.                 'lat' => $lat,
  207.                 'long' => $long,
  208.                 'address' => '',
  209.                 'gpsacc' => $gpsacc,
  210.                 'signal' => $signal,
  211.             ];
  212.             $ibeaconUpdateLog->setLat($lat);
  213.             $ibeaconUpdateLog->setLong($long);
  214.             $ibeaconUpdateLog->setGpsacc($gpsacc);
  215.             $ibeaconUpdateLog->setSignal($signal);
  216.             if (!$ibeacon->getLastSeen()) {
  217.                 $lastSeen = new IbeaconLastSeen();
  218.                 $lastSeen->setIbeacon($ibeacon);
  219.                 $this->getDoctrine()->getManager()->persist($lastSeen);
  220.                 $this->getDoctrine()->getManager()->flush();
  221.             } else {
  222.                 $lastSeen $ibeacon->getLastSeen();
  223.             }
  224.             $distance = (float)$ibeaconUpdateLog->getDistance();
  225.             if (!$ibeaconUpdateLog->getPrevHistory()['address'] || ($distance && $distance > (float)$this->ibeaconUpdateDistanceThreshold)) {
  226.                 $this->stopwatch->start('getAddress');
  227.                 $googleResponse $this->locationReader->addressTranslation($lat$long);
  228.                 $getAddressEvent $this->stopwatch->stop('getAddress');
  229.                 $getAddressEvent->ensureStopped();
  230.                 $executionTime['GOOGLE'] = $getAddressEvent->getDuration() / 1000.0;
  231.                 if ($googleResponse) {
  232.                     $googleResponseData json_decode($googleResponse->getContent(), true);
  233.                     $ibeaconUpdateLog->setStatus($googleResponseData['status']);
  234.                     $ibeaconUpdateLog->setError($googleResponseData['errorMessage']);
  235.                     if ($googleResponseData['status'] == 'OK') {
  236.                         $ibeaconUpdateLog->setCached($googleResponseData['cached']);
  237.                         if (isset($googleResponseData['addresses']) && isset($googleResponseData['addresses'][0])) {
  238.                             $ibeaconUpdateLog->setAddress($googleResponseData['addresses'][0]);
  239.                             $lastLocation['address'] = $googleResponseData['addresses'][0];
  240.                             $lastSeen->setLastAPILocation($lastLocation);
  241.                         } else {
  242.                             $ibeaconUpdateLog->setAddress("[NO ADDRESS CONVERTED FROM API]");
  243.                         }
  244.                     }
  245.                 }
  246.             } else {
  247.                 $address $ibeaconUpdateLog->getPrevHistory()['address'] ?  : "";
  248.                 $ibeaconUpdateLog->setStatus('SKIPPED');
  249.                 $ibeaconUpdateLog->setError('');
  250.                 $ibeaconUpdateLog->setCached(true);
  251.                 $ibeaconUpdateLog->setAddress($address);
  252.                 $lastLocation['address'] = $address;
  253.                 $lastSeen->setLastAPILocation($lastLocation);
  254.             }
  255.             $lastSeen->setLastAPISeenTimestamp($resultLastSeen);
  256.             $this->getDoctrine()->getManager()->persist($ibeaconUpdateLog);
  257.             $this->getDoctrine()->getManager()->persist($ibeacon);
  258.             $this->getDoctrine()->getManager()->flush();
  259.         }
  260.         return $executionTime;
  261.     }
  262.     public function updateRoute($ibeacon) {
  263.         $lastSeen $ibeacon->getLastSeen();
  264.         if ($lastSeen && $ibeacon) {
  265.             $lastAPILocation $ibeacon->getLastAPILocation();
  266.             $timestamp $lastSeen->getLastAPISeenTimestamp();
  267.             $lastSeenHistory = new IbeaconLastSeenHistory();
  268.             $lastSeenHistory->setLastSeen($lastSeen);
  269.             $lastSeenHistory->setAddress($lastAPILocation['address']);
  270.             $lastSeenHistory->setTimestamp($timestamp);
  271.             $lastSeenHistory->setLat($lastAPILocation['lat']);
  272.             $lastSeenHistory->setLong($lastAPILocation['long']);
  273.             $lastSeenHistory->setGpsacc($lastAPILocation['gpsacc']);
  274.             $lastSeenHistory->setSignal($lastAPILocation['signal']);
  275.             $this->getDoctrine()->getManager()->persist($lastSeenHistory);
  276.             $this->getDoctrine()->getManager()->persist($lastSeen);
  277.         }
  278.         $this->getDoctrine()->getManager()->persist($ibeacon);
  279.         $this->getDoctrine()->getManager()->flush();
  280.     }
  281.     /**
  282.      * @Route("/losts/{version}", methods={"GET"}, requirements={"version"="\d{10}"}, defaults={"version"=null})
  283.      */
  284.     public function loadLosts($version)
  285.     {
  286.         $result = [];
  287.         $lastupdate = new \DateTime();
  288.         if ($version) {
  289.             $result['ver'] = $version;
  290.             $lastupdate = (new \DateTime())->setTimestamp($version);
  291.         } else {
  292.             $result['ver'] = 0;
  293.         }
  294.         $result['patientlost'] = $this->getDoctrine()->getManager()->createQueryBuilder()
  295.             ->from('App\Entity\PatientLost''l')
  296.             ->join('App\Entity\PatientIbeacon''i'Join::WITH'i.patient = l.patient')
  297.             ->select('l.id AS lostid, i.mac AS beaconid, l.updatedAt AS date, l.found')
  298.             ->where('l.updatedAt > :lastUpdate')
  299.             ->andWhere('i.enabled = true')
  300.             ->orderBy('l.updatedAt''DESC')
  301.             ->addOrderBy('i.updatedAt''DESC')
  302.             ->getQuery()
  303.             ->execute([
  304.                 'lastUpdate' => $lastupdate
  305.             ]);
  306.         for ($i 0$i sizeof($result['patientlost']); $i++) {
  307.             $timestamp $result['patientlost'][$i]['date']->getTimestamp();
  308.             if ($result['ver'] < $timestamp) {
  309.                 $result['ver'] = $timestamp;
  310.             }
  311.             $result['patientlost'][$i]['date'] = date_format($result['patientlost'][$i]['date'], 'Y-m-d H:i:s');
  312.         }
  313.         return new JsonResponse($result200);
  314.     }
  315.     /**
  316.      * @Route("/search", methods={"GET"})
  317.      */
  318.     public function loadSearch(Request $request)
  319.     {
  320.         $jwt $request->headers->get('Authorization');
  321.         if (!isset(explode('.'$jwt)[1])) {
  322.             return new JsonResponse(array('code'=>'400','message'=>'Invalid JWT Token'));
  323.         }
  324.         $caregiverId json_decode(base64_decode(str_replace('_''/'str_replace('-','+',explode('.'$jwt)[1]))))->id;
  325.         $result = [];
  326.         $result['tags'] = $this->getDoctrine()->getManager()->createQueryBuilder()
  327.             ->from('App\Entity\Patient''p')
  328.             ->join('App\Entity\PatientIbeacon''i'Join::WITH'i.patient = p.id')
  329.             ->join('App\Entity\IbeaconLastSeen''s'Join::WITH's.ibeacon = i.id')
  330.             ->select("i.mac, s.lastAPILocation, s.lastAPISeenTimestamp")
  331.             ->where('p.caregiver = :caregiver')
  332.             ->andWhere('i.enabled = true')
  333.             ->orderBy('s.updatedAt''DESC')
  334.             ->addOrderBy('p.updatedAt''DESC')
  335.             ->getQuery()
  336.             ->execute([
  337.                 'caregiver' => $caregiverId
  338.             ]);
  339.         foreach ($result['tags'] as $key => $tag) {
  340.             $result['tags'][$key]['lastAPISeenTimestamp'] = (new \DateTime())->setTimestamp((int)$tag['lastAPISeenTimestamp'])->format('Y年m月d日 H:i:s');
  341.         }
  342.         return new JsonResponse($result200);
  343.     }
  344. }