Skip to content

Commit 3f47853

Browse files
committed
Refactor authentication and HTTP request handling; consolidate methods into dedicated files for improved organization and maintainability
1 parent 4da13b1 commit 3f47853

4 files changed

Lines changed: 379 additions & 356 deletions

File tree

PBAuth.cpp

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// PBAuth.cpp
2+
// Authentication, token management, and health check.
3+
4+
#include "PocketbaseExtended.h"
5+
6+
// ---------------------------------------------------------------------------
7+
// Token management
8+
// ---------------------------------------------------------------------------
9+
10+
void PocketbaseExtended::setAuthToken(const String& token) { _authToken = token; }
11+
String PocketbaseExtended::getAuthToken() const { return _authToken; }
12+
void PocketbaseExtended::clearAuthToken() { _authToken = ""; }
13+
14+
// ---------------------------------------------------------------------------
15+
// Auth endpoints
16+
// ---------------------------------------------------------------------------
17+
18+
PBResponse PocketbaseExtended::authWithPassword(const char* identity, const char* password) {
19+
if (_collection.length() == 0) {
20+
PBResponse r; r.ok = false; r.statusCode = 0;
21+
r.error = "No collection set. Call collection() first.";
22+
return r;
23+
}
24+
25+
String url = _baseUrl + "collections/" + _collection + "/auth-with-password";
26+
String body = "{\"identity\":\"";
27+
body += identity;
28+
body += "\",\"password\":\"";
29+
body += password;
30+
body += "\"}";
31+
32+
PBResponse resp = _request("POST", url, body);
33+
34+
// Auto-extract token from response body (no ArduinoJson dependency)
35+
if (resp.ok) {
36+
int idx = resp.body.indexOf("\"token\":\"");
37+
if (idx != -1) {
38+
idx += 9; // skip past `"token":"`
39+
int end = resp.body.indexOf("\"", idx);
40+
if (end != -1) {
41+
_authToken = resp.body.substring(idx, end);
42+
}
43+
}
44+
}
45+
46+
return resp;
47+
}
48+
49+
PBResponse PocketbaseExtended::authRefresh() {
50+
if (_collection.length() == 0) {
51+
PBResponse r; r.ok = false; r.statusCode = 0;
52+
r.error = "No collection set. Call collection() first.";
53+
return r;
54+
}
55+
if (_authToken.length() == 0) {
56+
PBResponse r; r.ok = false; r.statusCode = 0;
57+
r.error = "No token to refresh. Call authWithPassword() first.";
58+
return r;
59+
}
60+
61+
String url = _baseUrl + "collections/" + _collection + "/auth-refresh";
62+
PBResponse resp = _request("POST", url);
63+
64+
// Auto-update stored token on success
65+
if (resp.ok) {
66+
int idx = resp.body.indexOf("\"token\":\"");
67+
if (idx != -1) {
68+
idx += 9;
69+
int end = resp.body.indexOf("\"", idx);
70+
if (end != -1) {
71+
_authToken = resp.body.substring(idx, end);
72+
}
73+
}
74+
}
75+
76+
return resp;
77+
}
78+
79+
// ---------------------------------------------------------------------------
80+
// Health check
81+
// ---------------------------------------------------------------------------
82+
83+
PBResponse PocketbaseExtended::checkHealth() {
84+
String url = _baseUrl + "health";
85+
return _request("GET", url);
86+
}

PBRecords.cpp

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
// PBRecords.cpp
2+
// Record CRUD methods, URL helpers, and file URL builder.
3+
4+
#include "PocketbaseExtended.h"
5+
6+
// ---------------------------------------------------------------------------
7+
// Private URL helpers
8+
// ---------------------------------------------------------------------------
9+
10+
String PocketbaseExtended::_buildRecordsUrl(const char* recordId) {
11+
String url = _baseUrl + "collections/" + _collection + "/records";
12+
if (recordId != nullptr && strlen(recordId) > 0) {
13+
url += "/";
14+
url += recordId;
15+
}
16+
return url;
17+
}
18+
19+
String PocketbaseExtended::_appendParam(const String& url, const char* key, const char* value) {
20+
if (value == nullptr || strlen(value) == 0) return url;
21+
String result = url;
22+
result += (result.indexOf('?') == -1) ? "?" : "&";
23+
result += key;
24+
result += "=";
25+
result += value;
26+
return result;
27+
}
28+
29+
// ---------------------------------------------------------------------------
30+
// File URL builder (no HTTP request)
31+
// ---------------------------------------------------------------------------
32+
33+
String PocketbaseExtended::getFileUrl(const char* recordId,
34+
const char* filename,
35+
const char* thumb) {
36+
String url = _baseUrl + "files/" + _collection + "/" + recordId + "/" + filename;
37+
url = _appendParam(url, "thumb", thumb);
38+
return url;
39+
}
40+
41+
// ---------------------------------------------------------------------------
42+
// Extended record methods (return PBResponse)
43+
// ---------------------------------------------------------------------------
44+
45+
PBResponse PocketbaseExtended::getOneEx(const char* recordId,
46+
const char* expand,
47+
const char* fields) {
48+
if (recordId == nullptr || strlen(recordId) == 0) {
49+
PBResponse r; r.ok = false; r.statusCode = 0;
50+
r.error = "recordId is required";
51+
return r;
52+
}
53+
String url = _buildRecordsUrl(recordId);
54+
url = _appendParam(url, "expand", expand);
55+
url = _appendParam(url, "fields", fields);
56+
return _request("GET", url);
57+
}
58+
59+
PBResponse PocketbaseExtended::getListEx(const char* page,
60+
const char* perPage,
61+
const char* sort,
62+
const char* filter,
63+
const char* skipTotal,
64+
const char* expand,
65+
const char* fields) {
66+
String url = _buildRecordsUrl();
67+
url = _appendParam(url, "page", page);
68+
url = _appendParam(url, "perPage", perPage);
69+
url = _appendParam(url, "sort", sort);
70+
url = _appendParam(url, "filter", filter);
71+
url = _appendParam(url, "skipTotal", skipTotal);
72+
url = _appendParam(url, "expand", expand);
73+
url = _appendParam(url, "fields", fields);
74+
return _request("GET", url);
75+
}
76+
77+
PBResponse PocketbaseExtended::createEx(const String& requestBody) {
78+
String url = _buildRecordsUrl();
79+
return _request("POST", url, requestBody);
80+
}
81+
82+
PBResponse PocketbaseExtended::updateEx(const char* recordId, const String& requestBody) {
83+
if (recordId == nullptr || strlen(recordId) == 0) {
84+
PBResponse r; r.ok = false; r.statusCode = 0;
85+
r.error = "recordId is required";
86+
return r;
87+
}
88+
String url = _buildRecordsUrl(recordId);
89+
return _request("PATCH", url, requestBody);
90+
}
91+
92+
PBResponse PocketbaseExtended::deleteRecordEx(const char* recordId) {
93+
if (recordId == nullptr || strlen(recordId) == 0) {
94+
PBResponse r; r.ok = false; r.statusCode = 0;
95+
r.error = "recordId is required";
96+
return r;
97+
}
98+
String url = _buildRecordsUrl(recordId);
99+
return _request("DELETE", url);
100+
}
101+
102+
// ---------------------------------------------------------------------------
103+
// Convenience wrappers (return body String for backward compatibility)
104+
// ---------------------------------------------------------------------------
105+
106+
String PocketbaseExtended::getOne(const char* recordId,
107+
const char* expand,
108+
const char* fields) {
109+
return getOneEx(recordId, expand, fields).body;
110+
}
111+
112+
String PocketbaseExtended::getList(const char* page,
113+
const char* perPage,
114+
const char* sort,
115+
const char* filter,
116+
const char* skipTotal,
117+
const char* expand,
118+
const char* fields) {
119+
return getListEx(page, perPage, sort, filter, skipTotal, expand, fields).body;
120+
}
121+
122+
String PocketbaseExtended::create(const String& requestBody) {
123+
return createEx(requestBody).body;
124+
}
125+
126+
String PocketbaseExtended::update(const char* recordId, const String& requestBody) {
127+
return updateEx(recordId, requestBody).body;
128+
}
129+
130+
String PocketbaseExtended::deleteRecord(const char* recordId) {
131+
return deleteRecordEx(recordId).body;
132+
}

PBTransport.cpp

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
// PBTransport.cpp
2+
// HTTP transport layer: unified _request() dispatcher for ESP8266 and ESP32.
3+
4+
#include "PocketbaseExtended.h"
5+
6+
#if defined(ESP8266)
7+
# include <BearSSLHelpers.h>
8+
# include <ESP8266HTTPClient.h>
9+
# include <ESP8266WiFi.h>
10+
#elif defined(ESP32)
11+
# include <HTTPClient.h>
12+
# include <WiFi.h>
13+
# include <WiFiClientSecure.h>
14+
#endif
15+
16+
// ---------------------------------------------------------------------------
17+
// Unified HTTP request (GET / POST / PATCH / DELETE)
18+
// ---------------------------------------------------------------------------
19+
20+
PBResponse PocketbaseExtended::_request(const char* method,
21+
const String& url,
22+
const String& body) {
23+
PBResponse resp;
24+
resp.ok = false;
25+
resp.statusCode = 0;
26+
resp.body = "";
27+
resp.error = "";
28+
29+
if (_collection.length() == 0 &&
30+
url.indexOf("/collections/") == -1 &&
31+
url.indexOf("/health") == -1) {
32+
resp.error = "No collection set.";
33+
return resp;
34+
}
35+
36+
_debugPrint(String("[PB] ") + method + " " + url);
37+
38+
bool isHttps = url.startsWith("https");
39+
int httpCode = 0;
40+
41+
#if defined(ESP8266)
42+
HTTPClient http;
43+
BearSSL::WiFiClientSecure secureClient;
44+
WiFiClient plainClient;
45+
bool begun = false;
46+
47+
if (isHttps) {
48+
if (_insecureTLS) secureClient.setInsecure();
49+
begun = http.begin(secureClient, url);
50+
} else {
51+
begun = http.begin(plainClient, url);
52+
}
53+
54+
if (!begun) {
55+
resp.error = "Connection failed";
56+
_debugPrint("[PB] Connection failed");
57+
return resp;
58+
}
59+
60+
http.setTimeout(_timeout);
61+
62+
if (_authToken.length() > 0) {
63+
http.addHeader("Authorization", "Bearer " + _authToken);
64+
}
65+
66+
if (strcmp(method, "GET") == 0) {
67+
httpCode = http.GET();
68+
} else if (strcmp(method, "DELETE") == 0) {
69+
http.addHeader("Content-Length", "0");
70+
httpCode = http.sendRequest("DELETE");
71+
} else if (strcmp(method, "POST") == 0) {
72+
http.addHeader("Content-Type", "application/json");
73+
httpCode = http.POST(body);
74+
} else if (strcmp(method, "PATCH") == 0) {
75+
http.addHeader("Content-Type", "application/json");
76+
httpCode = http.sendRequest("PATCH", body);
77+
} else {
78+
resp.error = "Unknown HTTP method";
79+
http.end();
80+
return resp;
81+
}
82+
83+
if (httpCode > 0) {
84+
resp.statusCode = httpCode;
85+
resp.body = http.getString();
86+
resp.ok = (httpCode >= 200 && httpCode < 300);
87+
if (!resp.ok) resp.error = resp.body;
88+
_debugPrint(String("[PB] ") + httpCode + " " + resp.body);
89+
} else {
90+
resp.error = http.errorToString(httpCode);
91+
_debugPrint(String("[PB] Error: ") + resp.error);
92+
}
93+
94+
http.end();
95+
96+
#elif defined(ESP32)
97+
HTTPClient http;
98+
WiFiClientSecure secureClient;
99+
WiFiClient plainClient;
100+
bool begun = false;
101+
102+
if (isHttps) {
103+
if (_insecureTLS) secureClient.setInsecure();
104+
begun = http.begin(secureClient, url);
105+
} else {
106+
begun = http.begin(plainClient, url);
107+
}
108+
109+
if (!begun) {
110+
resp.error = "Connection failed";
111+
_debugPrint("[PB] Connection failed");
112+
return resp;
113+
}
114+
115+
http.setTimeout(_timeout);
116+
117+
if (_authToken.length() > 0) {
118+
http.addHeader("Authorization", "Bearer " + _authToken);
119+
}
120+
121+
if (strcmp(method, "GET") == 0) {
122+
httpCode = http.GET();
123+
} else if (strcmp(method, "DELETE") == 0) {
124+
http.addHeader("Content-Length", "0");
125+
httpCode = http.sendRequest("DELETE");
126+
} else if (strcmp(method, "POST") == 0) {
127+
http.addHeader("Content-Type", "application/json");
128+
httpCode = http.POST(body);
129+
} else if (strcmp(method, "PATCH") == 0) {
130+
http.addHeader("Content-Type", "application/json");
131+
httpCode = http.sendRequest("PATCH", body);
132+
} else {
133+
resp.error = "Unknown HTTP method";
134+
http.end();
135+
return resp;
136+
}
137+
138+
if (httpCode > 0) {
139+
resp.statusCode = httpCode;
140+
resp.body = http.getString();
141+
resp.ok = (httpCode >= 200 && httpCode < 300);
142+
if (!resp.ok) resp.error = resp.body;
143+
_debugPrint(String("[PB] ") + httpCode + " " + resp.body);
144+
} else {
145+
resp.error = http.errorToString(httpCode);
146+
_debugPrint(String("[PB] Error: ") + resp.error);
147+
}
148+
149+
http.end();
150+
151+
#else
152+
resp.error = "Unsupported platform";
153+
#endif
154+
155+
return resp;
156+
}

0 commit comments

Comments
 (0)