extend('polycast', function(/*Application $app*/){ // return new PolycastBroadcaster(); // }); //$factory->extend('polycast', function (Application $app, $config) { //app('Illuminate\Broadcasting\BroadcastManager')->extend('polycast', function (array $config) { //$broadcastManager->extend('polycast', function (array $config) { // This has to be done in BroadcastServiceProvider to avoid "Driver [driver] is not supported" error // $this->app[BroadcastManager::class]->extend('polycast', function (array $config) { // echo 'we are in extend'; // return new \App\Misc\PolycastBroadcaster(); // }); // $this->publishes([ // __DIR__.'/../dist/js/polycast.js' => public_path('vendor/polycast/polycast.js'), // __DIR__.'/../dist/js/polycast.min.js' => public_path('vendor/polycast/polycast.min.js'), // ], 'public'); // $this->publishes([ // __DIR__.'/../migrations/' => database_path('migrations') // ], 'migrations'); $this->app['router']->group(['middleware' => ['web'], 'prefix' => \Helper::getSubdirectory()], function ($router) { // establish connection and send current time $this->app['router']->post('polycast/connect', function (Request $request) { return ['status' => 'success', 'time' => Carbon::now()->toDateTimeString()]; }); // send payloads to requested browser $this->app['router']->post('polycast/receive', function (Request $request) { \Broadcast::auth($request); $query = \DB::table('polycast_events') ->select('*'); $channels = $request->get('channels', []); foreach ($channels as $channel => $events) { foreach ($events as $event) { // No need to add index to DB for this query. $query->orWhere(function ($query) use ($channel, $event, $request) { $query->where('channels', 'like', '%"'.$channel.'"%') ->where('event', '=', $event) // Recors are fetched starting from opening the page or from the last event. ->where('created_at', '>=', $request->get('time')); }); } } $collection = collect($query->get()); $payload = $collection->map(function ($item, $key) use ($request) { $created = \Carbon\Carbon::createFromFormat('Y-m-d H:i:s', $item->created_at); $requested = \Carbon\Carbon::createFromFormat('Y-m-d H:i:s', $request->get('time')); $item->channels = json_decode($item->channels, false); $item->payload = json_decode($item->payload, false); // Add extra data to the payload // This works only if payload has medius and thread_id $item->data = BroadcastNotification::fetchPayloadData($item->payload); $event_class = '\\'.$item->event; if (method_exists($event_class, "processPayload")) { // If user is not allowed to access this event, data will be sent to empty array. $item->payload = $event_class::processPayload($item->payload); } $item->delay = $requested->diffInSeconds($created); $item->requested_at = $requested->toDateTimeString(); return $item; }); // Reflash session data - otherwise on reply flash alert is not displayed // https://stackoverflow.com/questions/37019294/laravel-ajax-call-deletes-session-flash-data \Session::reflash(); $this->processConvView($request); \Eventy::action('polycast.receive', $request, $collection, $payload); return ['status' => 'success', 'time' => Carbon::now()->toDateTimeString(), 'payloads' => $payload]; }); }); } /** * Process conversation viewers. */ public function processConvView($request) { // Periodically save info indicating that user is still viewing the conversation. $viewing_conversation_id = null; if (!empty($request->data) && !empty($request->data['conversation_id'])) { $viewing_conversation_id = $request->data['conversation_id']; if (!empty($request->data['conversation_view_focus'])) { $conversation = Conversation::find($request->data['conversation_id']); if ($conversation) { \Eventy::action('conversation.view.focus', $conversation); } } } if ($viewing_conversation_id) { $user = auth()->user(); $now = Carbon::now(); $cache_key = 'conv_view_'.$user->id.'_'.$viewing_conversation_id; $cache_data = \Cache::get($cache_key); $view_date = null; $replying_changed = false; // t - date. // r - replying. if ($cache_data) { if (isset($cache_data['t']) && isset($cache_data['r'])) { $view_date = Carbon::createFromFormat('Y-m-d H:i:s', $cache_data['t']); // Let other users know that user started to reply. if (!(int)$cache_data['r'] && (int)$request->data['replying']) { // Started to reply. \App\Events\RealtimeConvView::dispatchSelf($viewing_conversation_id, $user, true); $replying_changed = true; } elseif ((int)$cache_data['r'] && !(int)$request->data['replying']) { // Finished to reply. \App\Events\RealtimeConvView::dispatchSelf($viewing_conversation_id, $user, false); $replying_changed = true; } } else { $replying_changed = true; } } if (!$cache_data || $replying_changed || ($view_date && $now->diffInSeconds($view_date) > 15)) { // Remember date of the last view in the cache. // Store for 2 minutes. $cache_data = [ 't' => $now->toDateTimeString(), 'r' => (int)$request->data['replying'] ]; \Cache::put($cache_key, $cache_data, 1); // Job could not detect when user finishes to view converrsation. // We are using cron. // \App\Jobs\CheckConvView::dispatch($viewing_conversation_id, $user->id) // ->delay(now()->addSeconds(25)) // ->onQueue(\Helper::QUEUE_DEFAULT); $conv_key = 'conv_view'; $conv_data = \Cache::get($conv_key) ?? []; $conv_data[$viewing_conversation_id][$user->id] = $cache_data; \Cache::put($conv_key, $conv_data, 20 /*minutes*/); // \DB::table('polycast_events')->insert([ // 'channels' => json_encode([['name' => 'conv.view']]), // 'event' => 'App\Events\RealtimeConvView', // 'payload' => json_encode([ // 'conversation_id' => $viewing_conversation_id, // 'reiterating' => true // ]), // 'created_at' => Carbon::now()->toDateTimeString(), // ]); } } } public function register() { } }