Arduino DLNA Server
Loading...
Searching...
No Matches
SubscriptionMgr.h
Go to the documentation of this file.
1#pragma once
2
3#include "basic/Str.h"
4#include "basic/Vector.h"
5#include "basic/StrPrint.h"
6#include "basic/Url.h"
7#include "http/HttpServer.h"
9
10namespace tiny_dlna {
11
12
24 Str callback_url; // as provided in CALLBACK header
25 uint32_t timeout_sec = 1800;
26 uint32_t seq = 0;
27 uint64_t expires_at = 0;
28};
29
46 public:
48
49 // Add or renew subscription. callbackUrl is formatted like "<http://host:port/path>"
50 // Returns SID (generated if new)
51 Str subscribe(const char* serviceId, const char* callbackUrl, uint32_t timeoutSec = 1800) {
52 // simple SID generation
53 char buffer[64];
54 snprintf(buffer, sizeof(buffer), "uuid:%lu", millis());
55 Str sid = buffer;
56
58 s.sid = sid;
59 s.callback_url = callbackUrl;
60 s.timeout_sec = timeoutSec;
61 s.seq = 0;
62 s.expires_at = millis() + (uint64_t)timeoutSec * 1000ULL;
63
64 getList(serviceId).push_back(s);
65 return sid;
66 }
67
68 bool unsubscribe(const char* serviceId, const char* sid) {
69 auto &list = getList(serviceId);
70 for (size_t i = 0; i < list.size(); ++i) {
71 if (StrView(list[i].sid).equals(sid)) {
72 list.erase(i);
73 return true;
74 }
75 }
76 return false;
77 }
78
79 // Publish a single state variable change to all subscribers of the service
80 void publishProperty(const char* serviceId, const char* varName, const char* value) {
81 auto &list = getList(serviceId);
82 for (int i = 0; i < list.size(); ++i) {
83 Subscription &sub = list[i];
84 // increment seq
85 sub.seq++;
86 // build body
87 StrPrint body;
88 body.reset();
89 body.write((const uint8_t*)"<?xml version=\"1.0\"?>\r\n", 27);
90 body.write((const uint8_t*)"<e:propertyset xmlns:e=\"urn:schemas-upnp-org:metadata-1-0/events\">\r\n", 68);
91 body.write((const uint8_t*)" <e:property>\r\n", 17);
92 body.write((const uint8_t*)" <", 6);
93 body.write((const uint8_t*)varName, strlen(varName));
94 body.write((const uint8_t*)">", 1);
95 body.write((const uint8_t*)value, strlen(value));
96 body.write((const uint8_t*)"</", 2);
97 body.write((const uint8_t*)varName, strlen(varName));
98 body.write((const uint8_t*)">\r\n", 3);
99 body.write((const uint8_t*)" </e:property>\r\n", 18);
100 body.write((const uint8_t*)"</e:propertyset>\r\n", 21);
101
102 // parse callback url
103 Url cbUrl(sub.callback_url.c_str());
104 DLNAHttpRequest http;
105 http.setHost(cbUrl.host());
106 http.setAgent("tiny-dlna-notify");
107 http.request().put("NT", "upnp:event");
108 http.request().put("NTS", "upnp:propchange");
109 // SEQ header name in some stacks is "SEQ" or "SID"; use "SEQ" here
110 char seqBuf[32];
111 snprintf(seqBuf, sizeof(seqBuf), "%d", sub.seq);
112 http.request().put("SEQ", seqBuf);
113 http.request().put("SID", sub.sid.c_str());
114 // post the notification
115 int rc = http.post(cbUrl, "text/xml", body.c_str(), body.length());
116 DlnaLogger.log(DlnaLogLevel::Info, "Notify %s -> %d", cbUrl.url(), rc);
117 }
118 }
119
120 protected:
121 // naive per-service storage using parallel vectors
124
125 Vector<Subscription>& getList(const char* serviceId) {
126 for (int i = 0; i < service_names.size(); ++i) {
127 if (StrView(service_names[i]).equals(serviceId)) return service_lists[i];
128 }
129 // not found: create
130 Str s = serviceId;
132 service_names.push_back(s);
133 service_lists.push_back(list);
134 return service_lists[service_lists.size() - 1];
135 }
136};
137
138} // namespace tiny_dlna
HttpHeader & put(const char *key, const char *value)
Definition: HttpHeader.h:103
Simple API to process get, put, post, del http requests I tried to use Arduino HttpClient,...
Definition: HttpRequest.h:21
virtual HttpRequestHeader & request()
Definition: HttpRequest.h:118
virtual void setAgent(const char *agent)
Definition: HttpRequest.h:120
void setHost(const char *host)
Definition: HttpRequest.h:40
virtual int post(Url &url, const char *mime, const char *data, int len=-1)
Definition: HttpRequest.h:61
void log(DlnaLogLevel current_level, const char *fmt...)
Print log message.
Definition: Logger.h:40
Print to a dynamic string.
Definition: StrPrint.h:12
const char * c_str()
Definition: StrPrint.h:38
size_t length()
Definition: StrPrint.h:40
size_t write(uint8_t ch) override
Definition: StrPrint.h:15
void reset()
Definition: StrPrint.h:42
A simple wrapper to provide string functions on char*. If the underlying char* is a const we do not a...
Definition: StrView.h:19
String implementation which keeps the data on the heap. We grow the allocated memory only if the copy...
Definition: Str.h:22
const char * c_str()
provides the string value as const char*
Definition: Str.h:187
Manages event subscriptions and notification delivery.
Definition: SubscriptionMgr.h:45
bool unsubscribe(const char *serviceId, const char *sid)
Definition: SubscriptionMgr.h:68
void publishProperty(const char *serviceId, const char *varName, const char *value)
Definition: SubscriptionMgr.h:80
Vector< Subscription > & getList(const char *serviceId)
Definition: SubscriptionMgr.h:125
Vector< Str > service_names
Definition: SubscriptionMgr.h:122
SubscriptionMgr()
Definition: SubscriptionMgr.h:47
Str subscribe(const char *serviceId, const char *callbackUrl, uint32_t timeoutSec=1800)
Definition: SubscriptionMgr.h:51
Vector< Vector< Subscription > > service_lists
Definition: SubscriptionMgr.h:123
URL parser which breaks a full url string up into its individual parts.
Definition: Url.h:18
const char * host()
Definition: Url.h:45
const char * url()
Definition: Url.h:43
Vector implementation which provides the most important methods as defined by std::vector....
Definition: Vector.h:21
Definition: Allocator.h:6
LoggerClass DlnaLogger
Definition: Logger.cpp:5
Represents a single event subscription for a service.
Definition: SubscriptionMgr.h:22
uint32_t timeout_sec
Definition: SubscriptionMgr.h:25
Str sid
Definition: SubscriptionMgr.h:23
uint32_t seq
Definition: SubscriptionMgr.h:26
Str callback_url
Definition: SubscriptionMgr.h:24
uint64_t expires_at
Definition: SubscriptionMgr.h:27