2 * Copyright (c) 2019, De Rais <derais@cock.li>
4 * Permission to use, copy, modify, and/or distribute this software for
5 * any purpose with or without fee is hereby granted, provided that the
6 * above copyright notice and this permission notice appear in all
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
23 #include <libwebsockets.h>
29 const char *program_name
= "cycon";
35 int len
= strlen(program_name
) + 7;
37 fprintf(stderr
, "usage: %s [ -s SERVER ] # like \"cytu.be\"\n",
39 fprintf(stderr
, "%*s [ -h ] # if website is http (not https)\n",
41 fprintf(stderr
, "%*s -c CHANNEL\n", len
, "");
44 /* LWS handling thread */
45 extern int cytube_lws_handler(struct lws
*wsi
, enum lws_callback_reasons reason
,
46 void *user
, void *in
, size_t len
);
52 struct state
volatile *s
= (struct state
volatile *) arg
;
53 char *ripped_host
= 0;
54 const struct lws_protocols p
[] = {
59 .callback
= cytube_lws_handler
, /* */
60 .per_session_data_size
= sizeof(struct state
), /* */
61 .rx_buffer_size
= 0, /* */
63 .user
= (void *) s
, /* */
64 .tx_packet_size
= 0, /* */
67 struct lws_context_creation_info info
= {
69 .options
= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT
, /* */
70 .port
= CONTEXT_PORT_NO_LISTEN
, /* */
73 struct lws_context
*context
= 0;
75 int sslf
= s
->https
? LCCSCF_USE_SSL
| LCCSCF_ALLOW_SELFSIGNED
: 0;
76 struct lws_client_connect_info cci
= {
79 .ssl_connection
= sslf
, /* */
80 .address
= s
->address
, /* */
81 .origin
= s
->address
, /* */
82 .protocol
= "sync", /* */
83 .userdata
= (void *) &s
, /* */
87 /* First, HTTP stuff in preparation for LWS */
88 if (cytube_get_session_cookie(cci
.address
, (s
->https
? "https" :
89 "http"), s
->channel_name
,
91 ERROR_MESSAGE("cannot extract ip-session cookie");
92 ERROR_MESSAGE("perhaps \"%s\" is not a channel?",
98 /* See cb_get_real_server */
100 ripped_host
= strdup(s
->socket_host
+ 8);
102 ripped_host
= strdup(s
->socket_host
+ 7);
105 if (!(ripped_host
)) {
109 for (char *p
= ripped_host
; *p
; ++p
) {
112 cci
.port
= strtoll(p
+ 1, 0, 0);
117 cci
.host
= ripped_host
;
118 cci
.address
= ripped_host
;
119 lws_set_log_level(0, 0);
120 cytube_set_cci_and_s(&cci
, s
);
122 if (!(context
= lws_create_context(&info
))) {
123 ERROR_MESSAGE("lws_create_context failed");
128 cci
.context
= context
;
129 s
->last_playlist_req
= time(0) + 120;
131 while (!s
->please_die
) {
132 if ((lret
= lws_service(context
, 1000)) < 0) {
136 /* Do we need to ping? */
139 if (s
->established
) {
140 if (s
->last_ping
+ (s
->ping_interval
/ 1000) <= now
) {
141 s
->must_write_ping
= 1;
145 if (s
->last_playlist_req
+ 120 <= now
) {
146 s
->must_ask_for_playlist
= 1;
147 s
->last_playlist_req
= now
;
151 /* Tell LWS we want to write */
152 if (s
->must_write_upgrade
||
153 s
->must_write_ping
||
154 s
->must_join_channel
||
155 s
->must_ask_for_playlist
) {
156 lws_callback_on_writable(wsi
);
160 lws_context_destroy(context
);
169 main(int argc
, char **argv
)
174 .address
= "cytu.be", .https
= 1,
176 char *server_arg
= 0;
177 char *channel_arg
= 0;
179 pthread_t lws_thread
= { 0 };
181 setlocale(LC_ALL
, "");
183 /* Parse arguments */
184 while ((opt
= getopt(argc
, argv
, "s:c:h")) != -1) {
190 channel_arg
= optarg
;
203 s
.address
= server_arg
;
211 s
.channel_name
= channel_arg
;
212 s
.playlist
.current_playing_uid
= -1;
214 if (ui_init(&s
) < 0) {
215 PERROR_MESSAGE("ui initialization error");
219 if (pthread_create(&lws_thread
, 0, lws_spin
, (void *) &s
)) {
220 PERROR_MESSAGE("pthread_create");
227 pthread_join(lws_thread
, 0);