MCPcopy Create free account
hub / github.com/NodeDB-Lab/nodedb / handle_psubscribe

Function handle_psubscribe

nodedb/src/control/server/resp/handler_pubsub.rs:128–227  ·  view source on GitHub ↗

Handle PSUBSCRIBE command: pattern-based subscription. Like SUBSCRIBE, but channel names are matched using glob patterns (`*` matches any string, `?` matches one character). Push messages use the `pmessage` type with 4 elements: `[pmessage, pattern, channel, payload]`.

(
    cmd: &RespCommand,
    session: &RespSession,
    state: &SharedState,
    stream: &mut ConnStream,
)

Source from the content-addressed store, hash-verified

126/// (`*` matches any string, `?` matches one character). Push messages
127/// use the `pmessage` type with 4 elements: `[pmessage, pattern, channel, payload]`.
128pub async fn handle_psubscribe(
129 cmd: &RespCommand,
130 session: &RespSession,
131 state: &SharedState,
132 stream: &mut ConnStream,
133) -> crate::Result<()> {
134 if cmd.argc() < 1 {
135 let resp = RespValue::err("ERR wrong number of arguments for 'psubscribe' command");
136 let bytes = resp.to_bytes();
137 stream
138 .write_all(&bytes)
139 .await
140 .map_err(|e| crate::Error::Bridge {
141 detail: format!("RESP write: {e}"),
142 })?;
143 return Ok(());
144 }
145
146 let patterns: Vec<String> = cmd
147 .args
148 .iter()
149 .filter_map(|a| std::str::from_utf8(a).ok().map(|s| s.to_string()))
150 .collect();
151
152 let mut subscription = state.change_stream.subscribe(None, Some(session.tenant_id));
153
154 // Send psubscribe confirmation for each pattern.
155 for (i, pattern) in patterns.iter().enumerate() {
156 let confirm = RespValue::array(vec![
157 RespValue::bulk_str("psubscribe"),
158 RespValue::bulk_str(pattern),
159 RespValue::integer((i + 1) as i64),
160 ]);
161 let bytes = confirm.to_bytes();
162 stream
163 .write_all(&bytes)
164 .await
165 .map_err(|e| crate::Error::Bridge {
166 detail: format!("RESP write: {e}"),
167 })?;
168 }
169
170 debug!(
171 patterns = ?patterns,
172 "RESP PSUBSCRIBE: entering pattern subscription mode"
173 );
174
175 // Subscription loop with glob matching.
176 loop {
177 match subscription.receiver.recv().await {
178 Ok(event) => {
179 // Check if event.collection matches ANY subscribed pattern.
180 let matched_pattern = patterns.iter().find(|p| {
181 crate::engine::kv::scan::glob_match(p.as_bytes(), event.collection.as_bytes())
182 });
183 let Some(pattern) = matched_pattern else {
184 continue;
185 };

Callers 1

handle_connectionFunction · 0.85

Calls 13

arrayFunction · 0.85
glob_matchFunction · 0.85
argcMethod · 0.80
collectMethod · 0.80
to_stringMethod · 0.80
errFunction · 0.50
to_bytesMethod · 0.45
iterMethod · 0.45
okMethod · 0.45
subscribeMethod · 0.45
recvMethod · 0.45
findMethod · 0.45

Tested by

no test coverage detected