StoryService.php 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. <?php
  2. namespace App\Services;
  3. use Illuminate\Support\Facades\Cache;
  4. use Illuminate\Support\Facades\Redis;
  5. use Illuminate\Support\Facades\Storage;
  6. use App\Story;
  7. use App\StoryView;
  8. class StoryService
  9. {
  10. const STORY_KEY = 'pf:services:stories:v1:';
  11. public static function get($id)
  12. {
  13. $account = AccountService::get($id);
  14. if(!$account) {
  15. return false;
  16. }
  17. $res = [
  18. 'profile' => [
  19. 'id' => (string) $account['id'],
  20. 'avatar' => $account['avatar'],
  21. 'username' => $account['username'],
  22. 'url' => $account['url']
  23. ]
  24. ];
  25. $res['stories'] = self::getStories($id);
  26. return $res;
  27. }
  28. public static function getById($id)
  29. {
  30. return Cache::remember(self::STORY_KEY . 'by-id:id-' . $id, 3600, function() use ($id) {
  31. return Story::find($id);
  32. });
  33. }
  34. public static function delById($id)
  35. {
  36. return Cache::forget(self::STORY_KEY . 'by-id:id-' . $id);
  37. }
  38. public static function getStories($id, $pid = null)
  39. {
  40. return Story::whereProfileId($id)
  41. ->latest()
  42. ->get()
  43. ->map(function($s) use($pid) {
  44. return [
  45. 'id' => (string) $s->id,
  46. 'type' => $s->type,
  47. 'duration' => 10,
  48. 'seen' => in_array($pid, self::views($s->id)),
  49. 'created_at' => $s->created_at->toAtomString(),
  50. 'expires_at' => $s->expires_at->toAtomString(),
  51. 'media' => url(Storage::url($s->path)),
  52. 'can_reply' => (bool) $s->can_reply,
  53. 'can_react' => (bool) $s->can_react,
  54. 'poll' => $s->type == 'poll' ? PollService::storyPoll($s->id) : null
  55. ];
  56. })
  57. ->toArray();
  58. }
  59. public static function views($id)
  60. {
  61. return StoryView::whereStoryId($id)
  62. ->pluck('profile_id')
  63. ->toArray();
  64. }
  65. public static function hasSeen($pid, $sid)
  66. {
  67. $key = self::STORY_KEY . 'seen:' . $pid . ':' . $sid;
  68. return Cache::remember($key, 3600, function() use($pid, $sid) {
  69. return StoryView::whereStoryId($sid)
  70. ->whereProfileId($pid)
  71. ->exists();
  72. });
  73. }
  74. public static function latest($pid)
  75. {
  76. return Cache::remember(self::STORY_KEY . 'latest:pid-' . $pid, 3600, function() use ($pid) {
  77. return Story::whereProfileId($pid)
  78. ->latest()
  79. ->first()
  80. ->id;
  81. });
  82. }
  83. public static function delLatest($pid)
  84. {
  85. Cache::forget(self::STORY_KEY . 'latest:pid-' . $pid);
  86. return Cache::forget('pf:stories:recent-self:' . $pid);
  87. }
  88. public static function addSeen($pid, $sid)
  89. {
  90. return Cache::put(self::STORY_KEY . 'seen:' . $pid . ':' . $sid, true, 86400);
  91. }
  92. public static function adminStats()
  93. {
  94. return Cache::remember('pf:admin:stories:stats', 300, function() {
  95. $total = Story::count();
  96. return [
  97. 'active' => [
  98. 'today' => Story::whereDate('created_at', now()->today())->count(),
  99. 'month' => Story::whereMonth('created_at', now()->month)->whereYear('created_at', now()->year)->count()
  100. ],
  101. 'total' => $total,
  102. 'remote' => [
  103. 'today' => Story::whereLocal(false)->whereDate('created_at', now()->today())->count(),
  104. 'month' => Story::whereLocal(false)->whereMonth('created_at', now()->month)->whereYear('created_at', now()->year)->count()
  105. ],
  106. 'storage' => [
  107. 'sum' => (int) Story::sum('size'),
  108. 'average' => (int) Story::avg('size')
  109. ],
  110. 'avg_spu' => $total ? (int) ($total / Story::groupBy('profile_id')->pluck('profile_id')->count()) : 'N/A',
  111. 'avg_duration' => (int) floor(Story::avg('duration')),
  112. 'avg_type' => $total ? Story::selectRaw('type, count(id) as count')->groupBy('type')->orderByDesc('count')->first()->type : 'N/A'
  113. ];
  114. });
  115. }
  116. public static function rotateQueue()
  117. {
  118. return Redis::smembers('pf:stories:rotate-queue');
  119. }
  120. public static function addRotateQueue($id)
  121. {
  122. return Redis::sadd('pf:stories:rotate-queue', $id);
  123. }
  124. public static function removeRotateQueue($id)
  125. {
  126. self::delById($id);
  127. return Redis::srem('pf:stories:rotate-queue', $id);
  128. }
  129. public static function reactIncrement($storyId, $profileId)
  130. {
  131. $key = 'pf:stories:react-counter:storyid-' . $storyId . ':profileid-' . $profileId;
  132. if(Redis::get($key) == null) {
  133. Redis::setex($key, 86400, 1);
  134. } else {
  135. return Redis::incr($key);
  136. }
  137. }
  138. public static function reactCounter($storyId, $profileId)
  139. {
  140. $key = 'pf:stories:react-counter:storyid-' . $storyId . ':profileid-' . $profileId;
  141. return (int) Redis::get($key) ?? 0;
  142. }
  143. }