tmp.spacet.me 데브로그 파트 2
19706 단어 dohackathon
이 작업을 단순화하기 위해 지금은 하드코딩된 외부 통합 목록을 사용하겠습니다. 이 목록을 사용자 지정 가능하게 만드는 것은 나중에 제공됩니다.
postMessage 프로토콜: 내가 사용하기로 결정한 메시징 프로토콜은 JSON-RPC 사양에 따라 Microsoft also uses it in its Language Server Protocol Specification 입니다.
결과
다음을 위한 통합을 구현했습니다.
json.spacet.me - JSON 뷰어
vdo.glitch.me - 비디오 플레이어
작동 방식: 외부 뷰어로 파일을 열 때 tmp.spacet.me는 세션 ID를 전달하는 새 창을 엽니다. 뷰어가 세션 ID를 로드하고 감지하면 오프너에 JSON-RPC 호출을 만들어 파일 내용을 가져옵니다.
구현 및 리팩토링
doing the simplest thing that could possibly work으로 시작하여
postMessage
처리 코드를 하드코딩했습니다. 여기서 코드는 TypeScript 컴파일러를 만족시키기 위해 유형 주장으로 가득 차 있습니다. 실험할 때 저는 이것이 좋은 일이라고 생각합니다. 나중에 정리하는 것을 잊지 마세요. 바로 다음에 올 것입니다.여기에서 전체 코드를 이해할 필요는 없습니다. 주석 주변의 코드만 살펴보세요.
window.addEventListener('message', async (e) => {
const fromWindow = (e.source as unknown) as Window
// Check for a method call.
if (e.data.method === 'tmp/getOpenedFile') {
// In this block, `e.data` is `any`, so no IntelliSense.
// (hovertip) const sessionId: any
const sessionId = e.data.params.sessionId
const session = sessionStorage[`session:${sessionId}`]
if (!session) return
const sessionState = JSON.parse(session)
const db = getFilesDatabase()
const doc = await db.get(sessionState.openedFile, {
binary: true,
attachments: true,
})
fromWindow.postMessage(
// Send a reply.
{
// Right now this object can be arbitrary payload;
// there's currently no type-checking here.
// So I might introduce a bug at some point...
jsonrpc: '2.0',
id: e.data.id,
result: {
blob: (doc._attachments.blob as any).data,
file: {
_rev: doc._rev,
_id: doc._id,
name: doc.name,
type: doc.type,
},
},
},
e.origin
)
}
})
이제 이것이 작동하는 동안 이러한 코드 작성 방식이 곧 문제를 일으킬 수 있음을 알 수 있습니다. 지금 당장 이러한 질문에 답하려면 코드가 명시적으로 언급되거나 문서화되지 않았기 때문에 코드 구현 방법을 읽어야 합니다.
이로 인해 인터페이스가 깨지기 쉬우므로 원하지 않습니다. 이 경우 정적 타이핑이 여기서 도움이 될 수 있다고 생각합니다. 그래서 계속해서 RPC 인터페이스를 문서화하는 방법으로 TypeScript 인터페이스를 만들었습니다. I wrote it in a way that I want to read it in the future.
interface RpcInterface extends JsonRpcDefinition {
'tmp/getOpenedFile': {
params: {
sessionId: string
}
result: {
blob: Blob
file: {
_rev: string
_id: string
name: string
type: string
}
}
}
}
이제 메시지 핸들러는 다음과 같습니다.
const rpc = new JsonRpcPayloadChecker<RpcInterface>()
window.addEventListener('message', async (e) => {
const fromWindow = (e.source as unknown) as Window
// Changed
if (rpc.isMethodCall(e.data, 'tmp/getOpenedFile')) {
// In this block, `e.data.params` shall have type
// `RpcInterface['tmp/getOpenedFile']` which is `{ sessionId: string }`
// (hovertip) const sessionId: string
const sessionId = e.data.params.sessionId
const session = sessionStorage[`session:${sessionId}`]
if (!session) return
const sessionState = JSON.parse(session)
const db = getFilesDatabase()
const doc = await db.get(sessionState.openedFile, {
binary: true,
attachments: true,
})
fromWindow.postMessage(
// Changed
rpc.replyResult(e.data, {
// In here, the type should flow to this object.
// So any deviations from the declared interface
// would cause a type-checking error.
blob: (doc._attachments.blob as any).data,
file: {
_rev: doc._rev,
_id: doc._id,
name: doc.name,
type: doc.type,
},
}),
e.origin
)
}
})
유형 흐름을 만들기 위해 다음은 해당 코드의 나머지 부분입니다. 이것은 내가 고급 유형을 작성하는 극소수의 장소 중 하나인 IMO입니다. IMO 고급 유형은 코드의 가독성을 떨어뜨리므로 격리된 장소에서 사용하는 것이 가장 좋습니다. TypeScript 세금은 문제지만 피하지 말고 관리합시다.
고급 유형을 사용할 때 내가 사용하는 리트머스 테스트는 다음과 같습니다. 다른 파일에서 유형 주석의 양이 줄어듭니까? 고급 유형이 코드베이스의 나머지 부분을 감염시키지 마십시오!
export class JsonRpcPayloadChecker<T extends JsonRpcDefinition> {
isMethodCall<K extends keyof T>(
message: unknown,
method: K
): message is JsonRpcMethodCall<K, T[K]['params']> {
return isJsonRpcMethodCall(message) && message.method === method
}
replyResult<K extends keyof T>(
message: JsonRpcMethodCall<K, any>,
result: T[K]['result']
) {
return {
jsonrpc: '2.0',
id: message.id,
result: result,
}
}
}
export interface JsonRpcDefinition {
[methodName: string]: {
params: any
result?: any
}
}
export interface JsonRpcMethodCall<MethodName, MethodParams> {
id: string
method: MethodName
params: MethodParams
}
function isJsonRpcMethodCall(
message: any
): message is { method: string; params: any } {
return message && message.method
}
Reference
이 문제에 관하여(tmp.spacet.me 데브로그 파트 2), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/dtinth/tmp-spacet-me-devlog-part-2-34hi텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)