Commit Diff


commit - 90dfaa0114b254eff2147735ed23dca09b571635
commit + 8285e71aecfd159643f1705f24709fc30a8cbda0
blob - 6e68ff331dae7881c9b5fdd240f869c658aedce6
blob + 2e293cfda482ac271343e8604d92b018614777f7
--- gotd/repo_write.c
+++ gotd/repo_write.c
@@ -1819,6 +1819,8 @@ render_notification(struct imsg *imsg, struct gotd_ims
 		    iev, imsg->fd);
 		break;
 	}
+
+	/* TODO send GOTD_IMSG_NOTIFY */
 
 	free(refname);
 	return err;
blob - d62256a1b20427e1dd67b05242a133f23a7ee0ea
blob + 133e70534548d1d8d4987921c6de3a96618c9da2
--- gotd/session.c
+++ gotd/session.c
@@ -55,6 +55,7 @@
 
 struct gotd_session_notif {
 	STAILQ_ENTRY(gotd_session_notif) entry;
+	int fd;
 	enum gotd_notification_action action;
 	char *refname;
 	struct got_object_id old_id;
@@ -460,6 +461,8 @@ queue_notification(struct got_object_id *old_id, struc
 	if (notif == NULL)
 		return got_error_from_errno("calloc");
 
+	notif->fd = -1;
+
 	if (old_id == NULL)
 		notif->action = GOTD_NOTIF_ACTION_CREATED;
 	else if (new_id == NULL)
@@ -485,8 +488,12 @@ done:
 	return err;
 }
 
+/*
+ * Forward notification content to the NOTIFY process.
+ * Request additional notifications from REPO_WRITE if any remain queued.
+ */
 static const struct got_error *
-send_notification(struct gotd_session_client *client, struct imsg *imsg)
+forward_notification(struct gotd_session_client *client, struct imsg *imsg)
 {
 	const struct got_error *err = NULL;
 	struct gotd_imsgev *iev = &client->repo_child_iev;
@@ -579,6 +586,63 @@ done:
 	    client->nref_updates == 0)
 		client->flush_disconnect = 1;
 	free(refname);
+	return err;
+}
+
+/* Request notification content from REPO_WRITE process. */
+static const struct got_error *
+request_notification(struct gotd_session_notif *notif)
+{
+	const struct got_error *err = NULL;
+	struct gotd_session_client *client = &gotd_session_client;
+	struct gotd_imsgev *iev = &client->repo_child_iev;
+	struct gotd_imsg_notification_content icontent;
+	struct ibuf *wbuf;
+	size_t len;
+	int fd;
+
+	fd = got_opentempfd();
+	if (fd == -1)
+		return got_error_from_errno("got_opentemp");
+
+	memset(&icontent, 0, sizeof(icontent));
+	icontent.client_id = client->id;
+
+	icontent.action = notif->action;
+	memcpy(&icontent.old_id, &notif->old_id, sizeof(notif->old_id));
+	memcpy(&icontent.new_id, &notif->new_id, sizeof(notif->new_id));
+	icontent.refname_len = strlen(notif->refname);
+
+	len = sizeof(icontent) + icontent.refname_len;
+	wbuf = imsg_create(&iev->ibuf, GOTD_IMSG_NOTIFY,
+	    gotd_session.proc_id, gotd_session.pid, len);
+	if (wbuf == NULL) {
+		err = got_error_from_errno("imsg_create NOTIFY");
+		goto done;
+	}
+	if (imsg_add(wbuf, &icontent, sizeof(icontent)) == -1) {
+		err = got_error_from_errno("imsg_add NOTIFY");
+		goto done;
+	}
+	if (imsg_add(wbuf, notif->refname, icontent.refname_len) == -1) {
+		err = got_error_from_errno("imsg_add NOTIFY");
+		goto done;
+	}
+
+	notif->fd = dup(fd);
+	if (notif->fd == -1) {
+		err = got_error_from_errno("dup");
+		goto done;
+	}
+
+	ibuf_fd_set(wbuf, fd);
+	fd = -1;
+
+	imsg_close(&iev->ibuf, wbuf);
+	gotd_imsg_event_add(iev);
+done:
+	if (err && fd != -1)
+		close(fd);
 	return err;
 }
 
@@ -591,6 +655,7 @@ update_ref(int *shut, struct gotd_session_client *clie
 	struct got_reference *ref = NULL;
 	struct gotd_imsg_ref_update iref;
 	struct got_object_id old_id, new_id;
+	struct gotd_session_notif *notif;
 	struct got_object_id *id = NULL;
 	char *refname = NULL;
 	size_t datalen;
@@ -736,7 +801,18 @@ done:
 		client->nref_updates--;
 		if (client->nref_updates == 0) {
 			send_refs_updated(client);
-			if (STAILQ_EMPTY(&notifications))
+			notif = STAILQ_FIRST(&notifications);
+			if (notif) {
+				err = request_notification(notif);
+				if (err) {
+					/*
+					 * Just log a warning.
+					 * Notifications are best-effort.
+					 */
+					log_warn("could not send notification: "
+					    "%s", err->msg);
+				}
+			} else
 				client->flush_disconnect = 1;
 		}
 
@@ -864,7 +940,7 @@ session_dispatch_repo_child(int fd, short event, void 
 				err = update_ref(&shut, client,
 				    gotd_session.repo->path, &imsg);
 			else if (do_notify)
-				err = send_notification(client, &imsg);
+				err = forward_notification(client, &imsg);
 			if (err)
 				log_warnx("uid %d: %s", client->euid, err->msg);
 		}
@@ -1839,6 +1915,8 @@ gotd_session_shutdown(void)
 	while (!STAILQ_EMPTY(&notifications)) {
 		notif = STAILQ_FIRST(&notifications);
 		STAILQ_REMOVE_HEAD(&notifications, entry);
+		if (notif->fd != -1)
+			close(notif->fd);
 		free(notif->refname);
 		free(notif);
 	}