Adapter::makeService()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 9.9
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace STS\StorageConnect\Drivers\Dropbox;
4
5
use Illuminate\Support\Arr;
6
use Illuminate\Support\Str;
7
use Kunnu\Dropbox\Dropbox;
8
use Kunnu\Dropbox\DropboxApp;
9
use Kunnu\Dropbox\Exceptions\DropboxClientException;
10
use Kunnu\Dropbox\Models\FileMetadata;
11
use STS\StorageConnect\Drivers\AbstractAdapter;
12
use STS\StorageConnect\Exceptions\UploadException;
13
use STS\StorageConnect\Models\CloudStorage;
14
use STS\StorageConnect\Models\Quota;
15
use STS\StorageConnect\UploadRequest;
16
use STS\StorageConnect\UploadResponse;
17
18
/**
19
 * @method Dropbox service()
20
 */
21
class Adapter extends AbstractAdapter
22
{
23
    /**
24
     * @var string
25
     */
26
    protected $driver = "dropbox";
27
28
    /**
29
     * @var string
30
     */
31
    protected $providerClass = Provider::class;
32
33
    /**
34
     * @param $user
35
     *
36
     * @return array
37
     */
38
    protected function mapUserDetails($user)
39
    {
40
        return [
41
            'name'  => $user->user['name']['display_name'],
42
            'email' => $user->user['email']
43
        ];
44
    }
45
46
    /**
47
     * @return \STS\StorageConnect\Models\Quota
48
     */
49
    public function getQuota()
50
    {
51
        $usage = $this->service()->getSpaceUsage();
52
53
        return new Quota(Arr::get($usage, "allocation.allocated", 0), Arr::get($usage, "used", 0));
54
    }
55
56
    /**
57
     * @param UploadRequest $request
58
     *
59
     * @return UploadResponse
60
     *
61
     */
62
    public function upload(UploadRequest $request)
63
    {
64
        try {
65
            if (Str::startsWith($request->getSourcePath(), "http")) {
66
                return new UploadResponse($request, $this->service()->saveUrl($request->getDestinationPath(), $request->getSourcePath()), true);
67
            }
68
69
            return new UploadResponse($request, $this->service()->upload(new File($request->getSourcePath()), $request->getDestinationPath(), [
70
                'mode' => 'overwrite'
71
            ]));
72
        } catch (DropboxClientException $e) {
73
            throw $this->handleUploadException($e, new UploadException($request, $e));
74
        }
75
    }
76
77
    /**
78
     * @param DropboxClientException $dropbox
79
     * @param UploadException $upload
80
     *
81
     * @return UploadException
82
     */
83
    protected function handleUploadException(DropboxClientException $dropbox, UploadException $upload)
84
    {
85
        // First check for connection failure
86
        if (Str::contains($dropbox->getMessage(), "Connection timed out")) {
87
            return $upload->retry("Connection timeout");
88
        }
89
90
        // Other known errors
91
        if (Str::contains($dropbox->getMessage(), "Async Job ID cannot be null")) {
92
            return $upload->message("Invalid upload job ID");
93
        }
94
95
        // See if we have a parseable error
96
        $error = json_decode($dropbox->getMessage(), true);
97
98
        if (!is_array($error)) {
99
            return $upload->retry("Unknown error uploading file to Dropbox: " . $dropbox->getMessage());
100
        }
101
102
        if (Str::contains(Arr::get($error, 'error_summary'), "insufficient_space")) {
103
            return $upload->disable("Dropbox account is full", CloudStorage::SPACE_FULL);
104
        }
105
106
        if (Str::contains(Arr::get($error, 'error_summary'), "invalid_access_token")) {
107
            return $upload->disable("Dropbox integration is invalid", CloudStorage::INVALID_TOKEN);
108
        }
109
110
        if (Str::contains(Arr::get($error, 'error_summary'), 'too_many_write_operations')) {
111
            return $upload->retry("Hit rate limit");
112
        }
113
114
        return $upload->retry("Unknown Dropbox exception: " . $dropbox->getMessage());
115
    }
116
117
    /**
118
     * @param UploadResponse $response
119
     *
120
     * @return UploadResponse
121
     */
122
    public function checkUploadStatus(UploadResponse $response)
123
    {
124
        try {
125
            $result = $this->service()->checkJobStatus($response->getOriginal());
126
        } catch (DropboxClientException $e) {
127
            throw $this->handleUploadException($e, new UploadException($response->getRequest(), $e));
128
        }
129
130
        if ($result instanceof FileMetadata) {
131
            return new UploadResponse($response->getRequest(), $result);
132
        }
133
134
        if ($result == "in_progress") {
135
            return $response;
136
        }
137
138
        if($result == "failed") {
139
            throw new UploadException($response->getRequest(), null, "Async upload failed");
140
        }
141
142
        // At this point we seem to have an unexpected result from Dropbox. If we have tried at least
143
        // 10 times, I think it's worth just failing at this point.
144
        if ($response->getStatusChecks() > 10) {
145
            throw new UploadException($response->getRequest(), null, 'Unexpected response from Dropbox when checking on async job: ' . $result);
146
        }
147
148
        // Ok then, we'll keep retrying
149
        return $response;
150
    }
151
152
    /**
153
     * @param string $remotePath
154
     *
155
     * @return bool
156
     */
157
    public function pathExists($remotePath)
158
    {
159
        try {
160
            return $this->service()->getMetadata($remotePath) instanceof FileMetadata;
161
        } catch(DropboxClientException $e) {
162
            return false;
163
        }
164
    }
165
166
    /**
167
     * @return Dropbox
168
     */
169
    protected function makeService()
170
    {
171
        $service = new Dropbox(
172
            new DropboxApp($this->config['client_id'], $this->config['client_secret']),
173
            ['random_string_generator' => 'openssl']
174
        );
175
176
        $service->setAccessToken(Arr::get($this->token, "access_token"));
177
178
        return $service;
179
    }
180
}