-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(messaging): post data through one-time requests (#28)
- Loading branch information
Showing
16 changed files
with
241 additions
and
457 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,118 +1,56 @@ | ||
import { AnyTRPCRouter } from '@trpc/server'; | ||
import { Messaging, createMessaging, fromChromePort } from './core'; | ||
import { Port, RequestHandler, StreamHandler, createMessaging } from './core'; | ||
import { applyMessagingHandler } from './core/trpc'; | ||
import { NAMESPACE, RequestHandler, StreamHandler, WebxMessage, isWebxMessage } from './shared'; | ||
|
||
export type WebxMessageMiddleware = ( | ||
message: WebxMessage, | ||
port: chrome.runtime.Port | ||
) => WebxMessage | false | void | Promise<WebxMessage | false | void>; | ||
|
||
// #region middlewares | ||
const senderInfoMiddleware: WebxMessageMiddleware = (message, port) => { | ||
return { | ||
from: port.name.slice(NAMESPACE.length), | ||
tabId: port.sender?.tab?.id, | ||
...message, | ||
}; | ||
}; | ||
// #endregion | ||
|
||
const middlewares = new Set<WebxMessageMiddleware>([senderInfoMiddleware]); | ||
|
||
async function applyMiddlewares(message: WebxMessage, port: chrome.runtime.Port) { | ||
for (const middleware of middlewares) { | ||
const modifiedMessage = await middleware(message, port); | ||
if (modifiedMessage === false) return message; | ||
if (modifiedMessage) message = modifiedMessage; | ||
} | ||
return message; | ||
} | ||
import { WebxMessage, isWebxMessage } from './shared'; | ||
|
||
export interface CustomHandlerOptions { | ||
requestHandler?: RequestHandler; | ||
streamHandler?: StreamHandler; | ||
} | ||
|
||
export function createCustomHandler({ | ||
requestHandler = () => Promise.reject(), | ||
streamHandler = (_, subscriber) => { | ||
subscriber.error('unimplemented'); | ||
}, | ||
}: CustomHandlerOptions) { | ||
const connections = new Set<Messaging>(); | ||
|
||
const listener = (port: chrome.runtime.Port): void => { | ||
if (!port.name.startsWith(NAMESPACE)) return; | ||
const messaging = createMessaging(fromChromePort(port), { | ||
async onRequest(message) { | ||
if (!isWebxMessage(message)) return Promise.reject('unknown message'); | ||
const webxMessage = await applyMiddlewares(message, port); | ||
const NAME = 'background'; | ||
|
||
if (!webxMessage.to) return requestHandler(webxMessage); | ||
|
||
for (const connection of connections) { | ||
if (connection.name === port.name) continue; | ||
if (connection.name.slice(NAMESPACE.length).startsWith(webxMessage.to)) { | ||
return connection.request(webxMessage); | ||
} | ||
} | ||
|
||
return Promise.reject('no target'); | ||
}, | ||
async onStream(message, subscriber) { | ||
if (!isWebxMessage(message)) return subscriber.error('unknown message'); | ||
const webxMessage = await applyMiddlewares(message, port); | ||
|
||
if (!webxMessage.to) return streamHandler(webxMessage, subscriber); | ||
const backgroundPort: Port = { | ||
name: NAME, | ||
onMessage(listener) { | ||
chrome.runtime.onMessage.addListener(listener); | ||
return () => { | ||
chrome.runtime.onMessage.removeListener(listener); | ||
}; | ||
}, | ||
send(message, originMessage?: Parameters<Parameters<typeof chrome.runtime.onMessage.addListener>[0]>) { | ||
if (!originMessage) return chrome.runtime.sendMessage(message); | ||
const [, sender] = originMessage; | ||
if (!sender.tab?.id) return chrome.runtime.sendMessage(message); | ||
chrome.tabs.sendMessage(sender.tab.id, message, { documentId: sender.documentId, frameId: sender.frameId }); | ||
}, | ||
}; | ||
|
||
for (const connection of connections) { | ||
if (connection.name === port.name) continue; | ||
if (connection.name.slice(NAMESPACE.length).startsWith(webxMessage.to)) { | ||
return connection.stream(webxMessage, subscriber); | ||
} | ||
} | ||
function shouldSkip(data: unknown) { | ||
if (!isWebxMessage(data)) return true; | ||
return !(!data.to || data.to === NAME); | ||
} | ||
|
||
subscriber.error('no target'); | ||
}, | ||
onDispose() { | ||
connections.delete(messaging); | ||
}, | ||
}); | ||
connections.add(messaging); | ||
}; | ||
chrome.runtime.onConnect.addListener(listener); | ||
return { | ||
connections, | ||
dispose() { | ||
chrome.runtime.onConnect.removeListener(listener); | ||
}, | ||
}; | ||
export function createCustomHandler({ requestHandler, streamHandler }: CustomHandlerOptions) { | ||
return createMessaging(backgroundPort, { | ||
intercept: (data: WebxMessage, abort) => (shouldSkip(data) ? abort : data.data), | ||
onRequest: requestHandler || (() => Promise.reject()), | ||
onStream: | ||
streamHandler || | ||
((_, subscriber) => { | ||
subscriber.error('unimplemented'); | ||
}), | ||
}); | ||
} | ||
|
||
export interface TrpcHandlerOptions<TRouter extends AnyTRPCRouter> { | ||
router: TRouter; | ||
} | ||
|
||
export function createTrpcHandler<TRouter extends AnyTRPCRouter>({ router }: TrpcHandlerOptions<TRouter>) { | ||
const connections = new Set<Messaging>(); | ||
|
||
const listener = (port: chrome.runtime.Port): void => { | ||
if (!port.name.startsWith(NAMESPACE)) return; | ||
const messaging = applyMessagingHandler({ | ||
port: fromChromePort(port), | ||
router, | ||
onDispose() { | ||
connections.delete(messaging); | ||
}, | ||
}); | ||
connections.add(messaging); | ||
}; | ||
chrome.runtime.onConnect.addListener(listener); | ||
return { | ||
connections, | ||
dispose() { | ||
chrome.runtime.onConnect.removeListener(listener); | ||
}, | ||
}; | ||
return applyMessagingHandler({ | ||
port: backgroundPort, | ||
router, | ||
intercept: (data: WebxMessage, abort) => (shouldSkip(data) ? abort : data.data), | ||
}); | ||
} |
Oops, something went wrong.