tilepad_plugin_sdk/
lib.rs1use clap::Parser;
2use futures::StreamExt;
3use inspector::Inspector;
4use plugin::Plugin;
5use protocol::ServerPluginMessage;
6use session::{PluginSessionHandle, PluginSessionRx};
7use subscription::Subscriptions;
8use tokio::spawn;
9use tokio_tungstenite::{connect_async, tungstenite::client::IntoClientRequest};
10
11use ws::WebSocketFuture;
12
13pub use tracing;
15pub use tracing_subscriber;
16
17pub mod inspector;
18pub mod plugin;
19pub mod protocol;
20pub mod session;
21mod subscription;
22mod ws;
23
24#[derive(Parser, Debug)]
25#[command(version, about, long_about = None)]
26struct Args {
27 #[arg(long)]
29 plugin_id: String,
30
31 #[arg(long)]
33 connect_url: String,
34}
35
36pub async fn start_plugin<P>(plugin: P)
37where
38 P: Plugin,
39{
40 let args = Args::parse();
42
43 let client_request = args
45 .connect_url
46 .into_client_request()
47 .expect("failed to create client request");
48 let (socket, _response) = connect_async(client_request)
49 .await
50 .expect("failed to connect to plugin server");
51
52 let (ws_future, ws_rx, ws_tx) = WebSocketFuture::new(socket);
54 spawn(async move {
55 if let Err(cause) = ws_future.await {
56 tracing::error!(?cause, "error running device websocket future");
57 }
58 });
59
60 let subscriptions = Subscriptions::default();
62
63 let handle = PluginSessionHandle::new(ws_tx, subscriptions.clone());
65
66 handle
68 .register(args.plugin_id)
69 .expect("failed to register plugin");
70
71 let mut msg_rx = PluginSessionRx::new(ws_rx);
72
73 while let Some(msg) = msg_rx.next().await {
74 let msg = match msg {
75 Ok(value) => value,
76 Err(cause) => {
77 tracing::error!(?cause, "error processing server message");
78 return;
79 }
80 };
81
82 subscriptions.apply(&msg);
84
85 match msg {
86 ServerPluginMessage::Registered { .. } => {
87 handle
88 .request_properties()
89 .expect("failed to request initial properties");
90
91 plugin.on_registered(&handle);
92 }
93 ServerPluginMessage::Properties { properties } => {
94 plugin.on_properties(&handle, properties);
95 }
96 ServerPluginMessage::TileClicked { ctx, properties } => {
97 plugin.on_tile_clicked(&handle, ctx, properties);
98 }
99 ServerPluginMessage::RecvFromInspector { ctx, message } => {
100 plugin.on_inspector_message(
101 &handle,
102 Inspector {
103 ctx,
104 session: handle.clone(),
105 },
106 message,
107 );
108 }
109 ServerPluginMessage::InspectorOpen { ctx } => {
110 plugin.on_inspector_open(
111 &handle,
112 Inspector {
113 ctx,
114 session: handle.clone(),
115 },
116 );
117 }
118 ServerPluginMessage::InspectorClose { ctx } => {
119 plugin.on_inspector_close(
120 &handle,
121 Inspector {
122 ctx,
123 session: handle.clone(),
124 },
125 );
126 }
127 ServerPluginMessage::DeepLink { ctx } => {
128 plugin.on_deep_link(&handle, ctx);
129 }
130 ServerPluginMessage::TileProperties {
131 tile_id,
132 properties,
133 } => {
134 plugin.on_tile_properties(&handle, tile_id, properties);
135 }
136 }
137 }
138
139 subscriptions.clear();
140}