3
3
namespace React \Filesystem \Uv ;
4
4
5
5
use React \EventLoop \ExtUvLoop ;
6
+ use React \EventLoop \Loop ;
6
7
use React \Filesystem \Node \FileInterface ;
7
8
use React \Filesystem \PollInterface ;
8
9
use React \Promise \Promise ;
11
12
12
13
final class File implements FileInterface
13
14
{
15
+ // private const READ_CHUNK_FIZE = 65536;
16
+ private const READ_CHUNK_FIZE = 1 ;
17
+
14
18
use StatTrait;
15
19
16
20
private ExtUvLoop $ loop ;
@@ -36,41 +40,102 @@ public function stat(): PromiseInterface
36
40
public function getContents (int $ offset = 0 , ?int $ maxlen = null ): PromiseInterface
37
41
{
38
42
$ this ->activate ();
39
- return new Promise (function (callable $ resolve ) use ($ offset , $ maxlen ): void {
40
- uv_fs_open ($ this ->uvLoop , $ this ->path . DIRECTORY_SEPARATOR . $ this ->name , UV ::O_RDONLY , 0 , function ($ fileDescriptor ) use ($ resolve , $ offset , $ maxlen ): void {
41
- uv_fs_fstat ($ this ->uvLoop , $ fileDescriptor , function ($ fileDescriptor , array $ stat ) use ($ resolve , $ offset , $ maxlen ): void {
42
- uv_fs_read ($ this ->uvLoop , $ fileDescriptor , $ offset , $ maxlen ?? (int )$ stat ['size ' ], function ($ fileDescriptor , string $ buffer ) use ($ resolve ): void {
43
- $ resolve ($ buffer );
44
- uv_fs_close ($ this ->uvLoop , $ fileDescriptor , function () {
45
- $ this ->deactivate ();
43
+ return $ this ->openFile (
44
+ $ this ->path . DIRECTORY_SEPARATOR . $ this ->name ,
45
+ UV ::O_RDONLY ,
46
+ 0 ,
47
+ )->then (
48
+ function ($ fileDescriptor ) use ($ offset , $ maxlen ): PromiseInterface {
49
+ $ buffer = '' ;
50
+ $ bufferLength = 0 ;
51
+ $ read = function (bool $ finalAttempt , int $ offset ) use ($ fileDescriptor , $ maxlen , &$ read , &$ buffer , &$ bufferLength ): PromiseInterface {
52
+ return new Promise (function (callable $ resolve ) use ($ fileDescriptor , $ offset , $ maxlen , $ finalAttempt , &$ read , &$ buffer , &$ bufferLength ): void {
53
+ \uv_fs_read ($ this ->uvLoop , $ fileDescriptor , $ offset , $ maxlen ?? self ::READ_CHUNK_FIZE , function ($ fileDescriptor , string $ contents ) use ($ resolve , $ maxlen , $ finalAttempt , &$ read , &$ buffer , &$ bufferLength ): void {
54
+ $ contentLength = strlen ($ contents );
55
+ $ buffer .= $ contents ;
56
+ $ bufferLength += $ contentLength ;
57
+
58
+ if (
59
+ ($ maxlen === null && $ finalAttempt ) ||
60
+ ($ maxlen !== null && $ bufferLength >= $ maxlen )
61
+ ) {
62
+ if ($ maxlen !== null && $ bufferLength > $ maxlen ) {
63
+ $ buffer = substr ($ buffer , 0 , $ maxlen );
64
+ }
65
+
66
+ $ resolve ($ this ->closeOpenFile ($ fileDescriptor )->then (function () use ($ buffer ): string {
67
+ $ this ->deactivate ();
68
+
69
+ return $ buffer ;
70
+ }));
71
+ } else if ($ maxlen === null && !$ finalAttempt && $ contentLength === 0 ) {
72
+ $ resolve ($ read (true , $ bufferLength ));
73
+ } else {
74
+ $ resolve ($ read (false , $ bufferLength ));
75
+ }
46
76
});
47
77
});
48
- });
49
- });
50
- });
78
+ };
79
+
80
+ return $ read (false , $ offset );
81
+ }
82
+ );
51
83
}
52
84
53
85
public function putContents (string $ contents , int $ flags = 0 )
54
86
{
55
87
$ this ->activate ();
56
- return new Promise ( function ( callable $ resolve ) use ( $ contents , $ flags ): void {
57
- uv_fs_open (
58
- $ this -> uvLoop ,
59
- $ this -> path . DIRECTORY_SEPARATOR . $ this -> name ,
60
- (( $ flags & \ FILE_APPEND ) == \ FILE_APPEND ) ? UV :: O_RDWR | UV :: O_CREAT | UV :: O_APPEND : UV :: O_RDWR | UV :: O_CREAT ,
61
- 0644 ,
62
- function ($ fileDescriptor ) use ($ resolve , $ contents , $ flags ): void {
88
+ return $ this -> openFile (
89
+ $ this -> path . DIRECTORY_SEPARATOR . $ this -> name ,
90
+ (( $ flags & \ FILE_APPEND ) == \ FILE_APPEND ) ? UV :: O_RDWR | UV :: O_CREAT | UV :: O_APPEND : UV :: O_RDWR | UV :: O_CREAT ,
91
+ 0644 ,
92
+ )-> then (
93
+ function ( $ fileDescriptor ) use ( $ contents ): PromiseInterface {
94
+ return new Promise ( function (callable $ resolve ) use ($ contents , $ fileDescriptor ): void {
63
95
uv_fs_write ($ this ->uvLoop , $ fileDescriptor , $ contents , 0 , function ($ fileDescriptor , int $ bytesWritten ) use ($ resolve ): void {
64
- $ resolve ($ bytesWritten );
65
- uv_fs_close ($ this ->uvLoop , $ fileDescriptor , function () {
96
+ $ resolve ($ this ->closeOpenFile ($ fileDescriptor )->then (function () use ($ bytesWritten ): int {
66
97
$ this ->deactivate ();
67
- });
98
+ return $ bytesWritten ;
99
+ }));
68
100
});
69
101
}
70
102
);
71
103
});
72
104
}
73
105
106
+ private function openFile (string $ path , int $ flags , int $ mode ): PromiseInterface
107
+ {
108
+ $ this ->activate ();
109
+ return new Promise (function (callable $ resolve ) use ($ path , $ flags , $ mode ): void {
110
+ uv_fs_open (
111
+ $ this ->uvLoop ,
112
+ $ this ->path . DIRECTORY_SEPARATOR . $ this ->name ,
113
+ $ flags ,
114
+ $ mode ,
115
+ function ($ fileDescriptor ) use ($ resolve ): void {
116
+ $ this ->deactivate ();
117
+ $ resolve ($ fileDescriptor );
118
+ }
119
+ );
120
+ });
121
+ }
122
+
123
+ private function closeOpenFile ($ fileDescriptor ): PromiseInterface
124
+ {
125
+ $ this ->activate ();
126
+ return new Promise (function (callable $ resolve ) use ($ fileDescriptor ) {
127
+ try {
128
+ uv_fs_close ($ this ->uvLoop , $ fileDescriptor , function () use ($ resolve ) {
129
+ $ this ->deactivate ();
130
+ $ resolve ();
131
+ });
132
+ } catch (\Throwable $ error ) {
133
+ $ this ->deactivate ();
134
+ throw $ error ;
135
+ }
136
+ });
137
+ }
138
+
74
139
public function unlink (): PromiseInterface
75
140
{
76
141
$ this ->activate ();
0 commit comments