Switch to unified view

a/src/mediaserver/cdplugins/plgwithslave.cxx b/src/mediaserver/cdplugins/plgwithslave.cxx
...
...
65
// stuck forever.
65
// stuck forever.
66
static const int read_timeout(60);
66
static const int read_timeout(60);
67
67
68
class PlgWithSlave::Internal {
68
class PlgWithSlave::Internal {
69
public:
69
public:
70
    Internal(PlgWithSlave *_plg, const string& exe, const string& hst,
70
    Internal(PlgWithSlave *_plg, const string& hst,
71
             int prt, const string& pp)
71
             int prt, const string& pp)
72
        : plg(_plg), cmd(read_timeout), exepath(exe), upnphost(hst),
72
        : plg(_plg), cmd(read_timeout), upnphost(hst),
73
          upnpport(prt), pathprefix(pp), laststream(this) { }
73
          upnpport(prt), pathprefix(pp), laststream(this) { }
74
74
75
    bool maybeStartCmd();
75
    bool maybeStartCmd();
76
76
77
    PlgWithSlave *plg;
77
    PlgWithSlave *plg;
78
    CmdTalk cmd;
78
    CmdTalk cmd;
79
    string exepath;
80
    // Upnp Host and port. This would only be used to generate URLs *if*
79
    // Upnp Host and port. This would only be used to generate URLs *if*
81
    // we were using the libupnp miniserver. We currently use
80
    // we were using the libupnp miniserver. We currently use
82
    // microhttp because it can do redirects
81
    // microhttp because it can do redirects
83
    string upnphost;
82
    string upnphost;
84
    int upnpport;
83
    int upnpport;
...
...
89
    StreamHandle laststream;
88
    StreamHandle laststream;
90
};
89
};
91
90
92
// microhttpd daemon handle. There is only one of these, and one port, we find
91
// microhttpd daemon handle. There is only one of these, and one port, we find
93
// the right plugin by looking at the url path.
92
// the right plugin by looking at the url path.
94
static struct MHD_Daemon *mhd;
93
static struct MHD_Daemon *o_mhd;
95
94
96
// Microhttpd connection handler. We re-build the complete url + query
95
// Microhttpd connection handler. We re-build the complete url + query
97
// string (&trackid=value), use this to retrieve a service URL
96
// string (&trackid=value), use this to retrieve a service URL
98
// (tidal/qobuz...), and redirect to it (HTTP). A previous version
97
// (tidal/qobuz...), and redirect to it (HTTP). A previous version
99
// handled rtmp streams, and had to read them. Look up the history if
98
// handled rtmp streams, and had to read them. Look up the history if
...
...
116
           " version " << version << endl);
115
           " version " << version << endl);
117
116
118
    // The 'plgi' here is just whatever plugin started up the httpd task
117
    // The 'plgi' here is just whatever plugin started up the httpd task
119
    // We just use it to find the appropriate plugin for this path,
118
    // We just use it to find the appropriate plugin for this path,
120
    // and then dispatch the request.
119
    // and then dispatch the request.
121
    PlgWithSlave::Internal *plgi = (PlgWithSlave::Internal*)cls;
120
    CDPluginServices *cdpsrv = (CDPluginServices*)cls;
122
    PlgWithSlave *realplg =
121
    PlgWithSlave *realplg =
123
        dynamic_cast<PlgWithSlave*>(plgi->plg->m_services->getpluginforpath(url));
122
        dynamic_cast<PlgWithSlave*>(cdpsrv->getpluginforpath(url));
124
    if (nullptr == realplg) {
123
    if (nullptr == realplg) {
125
        LOGERR("answer_to_connection: no plugin for path [" << url << endl);
124
        LOGERR("answer_to_connection: no plugin for path [" << url << endl);
126
        return MHD_NO;
125
        return MHD_NO;
127
    }
126
    }
128
127
...
...
179
static int accept_policy(void *, const struct sockaddr* sa, socklen_t addrlen)
178
static int accept_policy(void *, const struct sockaddr* sa, socklen_t addrlen)
180
{
179
{
181
    return MHD_YES;
180
    return MHD_YES;
182
}
181
}
183
182
184
// Called once for starting the Python program and do other initialization.
183
// Static
185
bool PlgWithSlave::Internal::maybeStartCmd()
184
bool PlgWithSlave::startPluginCmd(CmdTalk& cmd, const string& appname,
185
                                  const string& host, unsigned int port,
186
                                  const string& pathpref)
186
{
187
{
187
    if (cmd.running()) {
188
    string pythonpath = string("PYTHONPATH=") +
189
        path_cat(g_datadir, "cdplugins") + ":" +
190
        path_cat(g_datadir, "cdplugins/pycommon") + ":" +
191
        path_cat(g_datadir, "cdplugins/" + appname);
192
    string configname = string("UPMPD_CONFIG=") + g_configfilename;
193
    stringstream ss;
194
    ss << host << ":" << port;
195
    string hostport = string("UPMPD_HTTPHOSTPORT=") + ss.str();
196
    string pp = string("UPMPD_PATHPREFIX=") + pathpref;
197
    string exepath = path_cat(g_datadir, "cdplugins");
198
    exepath = path_cat(exepath, appname);
199
    exepath = path_cat(exepath, appname + "-app" + ".py");
200
201
    if (!cmd.startCmd(exepath, {/*args*/},
202
                      /* env */ {pythonpath, configname, hostport, pp})) {
203
        LOGERR("PlgWithSlave::maybeStartCmd: startCmd failed\n");
204
        return false;
205
    }
188
        return true;
206
    return true;
189
    }
207
}
190
208
191
    int port = CDPluginServices::default_microhttpport();
209
// Static
192
    string sport;
210
bool PlgWithSlave::maybeStartMHD(CDPluginServices *cdsrv)
193
    if (plg->m_services->config_get("plgmicrohttpport", sport)) {
211
{
194
        port = atoi(sport.c_str());
195
    }
196
    if (nullptr == mhd) {
212
    if (nullptr == o_mhd) {
197
213
        int port = CDPluginServices::microhttpport();
198
        // Start the microhttpd daemon. There can be only one, and it
214
        // Start the microhttpd daemon. There can be only one, and it
199
        // is started with a context handle which points to whatever
215
        // is started with a context handle which points to whatever
200
        // plugin got there first. The callback will only use the
216
        // plugin got there first. The callback will only use the
201
        // handle to get to the plugin services, and retrieve the
217
        // handle to get to the plugin services, and retrieve the
202
        // appropriate plugin based on the url path prefix.
218
        // appropriate plugin based on the url path prefix.
203
        LOGDEB("PlgWithSlave: starting httpd on port "<< port << endl);
219
        LOGDEB("PlgWithSlave: starting httpd on port "<< port << endl);
204
        mhd = MHD_start_daemon(
220
        o_mhd = MHD_start_daemon(
205
            MHD_USE_THREAD_PER_CONNECTION,
221
            MHD_USE_THREAD_PER_CONNECTION,
206
            //MHD_USE_SELECT_INTERNALLY, 
222
            //MHD_USE_SELECT_INTERNALLY, 
207
            port, 
223
            port, 
208
            /* Accept policy callback and arg */
224
            /* Accept policy callback and arg */
209
            accept_policy, NULL, 
225
            accept_policy, NULL, 
210
            /* handler and arg */
226
            /* handler and arg */
211
            &answer_to_connection, this, 
227
            &answer_to_connection, cdsrv,
212
            MHD_OPTION_END);
228
            MHD_OPTION_END);
213
        if (nullptr == mhd) {
229
        if (nullptr == o_mhd) {
214
            LOGERR("PlgWithSlave: MHD_start_daemon failed\n");
230
            LOGERR("PlgWithSlave: MHD_start_daemon failed\n");
215
            return false;
231
            return false;
216
        }
232
        }
217
    }
233
    }
234
    return true;
235
}
236
237
// Called once for starting the Python program and do other initialization.
238
bool PlgWithSlave::Internal::maybeStartCmd()
239
{
240
    if (cmd.running()) {
241
        return true;
218
    
242
    }
219
    string pythonpath = string("PYTHONPATH=") +
243
    if (!maybeStartMHD(this->plg->m_services)) {
220
        path_cat(g_datadir, "cdplugins") + ":" +
221
        path_cat(g_datadir, "cdplugins/pycommon") + ":" +
222
        path_cat(g_datadir, "cdplugins/" + plg->m_name);
223
    string configname = string("UPMPD_CONFIG=") + g_configfilename;
224
    stringstream ss;
225
    ss << upnphost << ":" << port;
226
    string hostport = string("UPMPD_HTTPHOSTPORT=") + ss.str();
227
    string pp = string("UPMPD_PATHPREFIX=") + pathprefix;
228
    if (!cmd.startCmd(exepath, {/*args*/},
229
                      /* env */ {pythonpath, configname, hostport, pp})) {
230
        LOGERR("PlgWithSlave::maybeStartCmd: startCmd failed\n");
231
        return false;
244
        return false;
232
    }
245
    }
233
    return true;
246
    int port = CDPluginServices::microhttpport();
247
    return startPluginCmd(cmd, plg->m_name, upnphost, port, pathprefix);
234
}
248
}
235
249
236
bool PlgWithSlave::startInit()
250
bool PlgWithSlave::startInit()
237
{
251
{
238
    return m && m->maybeStartCmd();
252
    return m && m->maybeStartCmd();
...
...
279
293
280
294
281
PlgWithSlave::PlgWithSlave(const string& name, CDPluginServices *services)
295
PlgWithSlave::PlgWithSlave(const string& name, CDPluginServices *services)
282
    : CDPlugin(name, services)
296
    : CDPlugin(name, services)
283
{
297
{
284
    string exepath = path_cat(g_datadir, "cdplugins");
285
    exepath = path_cat(exepath, name);
286
    exepath = path_cat(exepath, name + "-app" + ".py");
287
288
    m = new Internal(this, exepath,
298
    m = new Internal(this,
289
                     services->getupnpaddr(this),
299
                     services->getupnpaddr(this),
290
                     services->getupnpport(this),
300
                     services->getupnpport(this),
291
                     services->getpathprefix(this));
301
                     services->getpathprefix(this));
292
}
302
}
293
303