1
+ <?php
2
+ /**
3
+ * Created by Cestbon.
4
+ * Author Cestbon <[email protected] >
5
+ * Date 2021-08-20 15:45
6
+ */
7
+
8
+ namespace Chenpkg \Idempotent ;
9
+
10
+ use Chenpkg \Idempotent \Exceptions \RepeatRequestException ;
11
+ use Closure ;
12
+ use Illuminate \Http \Request ;
13
+ use Illuminate \Support \Facades \Cache ;
14
+
15
+ class IdempotentMiddleware
16
+ {
17
+ protected $ config ;
18
+
19
+ const PLACE_HOLDER = 'idempotent_place_holder ' ;
20
+
21
+ public function handle (Request $ request , Closure $ next )
22
+ {
23
+ $ this ->config = config ('idempotent ' );
24
+
25
+ if (! in_array ($ request ->method (), $ this ->config ['methods ' ])) {
26
+ return $ next ($ request );
27
+ }
28
+
29
+ $ idempotentKey = $ this ->getIdempotentKey ();
30
+
31
+ if (! $ idempotentKey ) {
32
+ return $ next ($ request );
33
+ }
34
+
35
+ $ this ->repeated ($ idempotentKey );
36
+
37
+ return $ next ($ request );
38
+ }
39
+
40
+ /**
41
+ * @param $request
42
+ * @param $response
43
+ */
44
+ public function terminate ($ request , $ response )
45
+ {
46
+ Cache::forget ($ this ->getCacheKey ($ request ->header ($ this ->config ['header_name ' ])));
47
+ }
48
+
49
+ /**
50
+ * @param $key
51
+ * @return string
52
+ */
53
+ protected function getCacheKey ($ key )
54
+ {
55
+ return 'idempotent_key: ' .$ key ;
56
+ }
57
+
58
+ /**
59
+ * @param $idempotentKey
60
+ * @return true
61
+ * @throws RepeatRequestException
62
+ */
63
+ protected function repeated ($ idempotentKey )
64
+ {
65
+ $ value = Cache::get ($ this ->getCacheKey ($ idempotentKey ));
66
+
67
+ if ($ value == static ::PLACE_HOLDER ) {
68
+ throw new RepeatRequestException ('Your request is still being processed. ' );
69
+ }
70
+
71
+ $ seconds = (int )$ this ->config ['seconds ' ];
72
+ $ seconds = $ seconds > 0 ? $ seconds : null ;
73
+
74
+ Cache::put ($ this ->getCacheKey ($ idempotentKey ), static ::PLACE_HOLDER , $ seconds );
75
+
76
+ return true ;
77
+ }
78
+
79
+ /**
80
+ * @return array|string|null
81
+ */
82
+ protected function getIdempotentKey ()
83
+ {
84
+ return $ this ->config ['forcible ' ] ? $ this ->generateIdempotentKey () : request ()->header ($ this ->config ['header_name ' ]);
85
+ }
86
+
87
+ /**
88
+ * @return string
89
+ */
90
+ protected function generateIdempotentKey ()
91
+ {
92
+ $ user = $ this ->resolveUser ();
93
+
94
+ $ idempotentKey = $ user ? $ user ->getAuthIdentifier ().request () : request ()->ip ().request ();
95
+ $ idempotentKey = sha1 ($ idempotentKey );
96
+
97
+ request ()->headers ->set (config ('idempotent.header_name ' ), $ idempotentKey );
98
+
99
+ return $ idempotentKey ;
100
+ }
101
+
102
+ /**
103
+ * @return mixed|null
104
+ */
105
+ protected function resolveUser ()
106
+ {
107
+ $ user = null ;
108
+
109
+ $ resolveUser = $ this ->config ['resolve_user ' ];
110
+
111
+ if ($ resolveUser instanceof Closure && $ result = app ()->call ($ resolveUser )) {
112
+ $ user = $ result ;
113
+ }
114
+
115
+ return $ user ;
116
+ }
117
+ }
0 commit comments