-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[protocol] Pre-session handshake #53
Conversation
export interface ServiceContext { | ||
state: object | unknown; | ||
} | ||
export interface ServiceContext {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
idk why this included state before, we have a separate type for this
type: Type.Literal('CLOSE'), | ||
}); | ||
|
||
export const PROTOCOL_VERSION = 'v1'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❤️
transport/impls/stdio/client.ts
Outdated
@@ -36,15 +36,14 @@ export class StdioClientTransport extends Transport<StreamConnection> { | |||
async createNewOutgoingConnection(to: TransportClientId) { | |||
log?.info(`${this.clientId} -- establishing a new stream to ${to}`); | |||
const conn = new StreamConnection(this.input, this.output); | |||
conn.onData((data) => this.handleMsg(this.parseMsg(data))); | |||
conn.onData(this.receiveWithBootSequence(conn)); | |||
const cleanup = () => { | |||
this.onDisconnect(conn, to); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mentioned in the other PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I'm missing something, but why is the implementer responsible for calling
onConnect
andonDisconnect
? Why don't they just callconnect
and which calls the implementedcreateNewOutgoingConnection
and returns aConnection
. Then insideconnect
we use the returned connection and pass it toonConnect
andonDisconnect
, this would probably require us to add more event listeners to theConnection
interface like i mentioned in another comment.
82f25d2
to
a6ff717
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
left a big comment that combines semantic neatness and also addresses pid2 version drift for the first release of this.
b89e76f
to
835f458
Compare
835f458
to
5543ed1
Compare
… .onConnect and .onDisconnect
transport/transport.ts
Outdated
this.clientId | ||
} -- received invalid handshake resp: ${JSON.stringify(parsed)}`, | ||
); | ||
return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we really return
here? what happens in the scenario i outlined in the main PR? (multiplayers, one workspace is older than the other, both connecting to a newer or older pid2)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hm I can't find the comment in the main PR you are referring to, can you reiterate? oh nvm the comment in this pr haha found it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
imo we shouldn't worry about mismatched river versions until after this PR lands
- not receiving a handshake message should be treated as fatal/refuse the connection and will help us find mistakes faster
- pid2 flag audience is small enough (3 people) that just refreshing client for now is fine
- for ai chat, we can bake that compatability into the python river server
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh so essentially implement what i'm suggesting but only in ai chat. that seems reasonable, although i'd like us to start to build the backwards-compatibility muscle before it starts becoming load-bearing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah that makes sense, i think once this change is in place i'd be more more comfortable as this makes backwards-compatability much easier and less brittle than what we have now 👍
abstract addDataListener(cb: (msg: Uint8Array) => void): void; | ||
abstract removeDataListener(cb: (msg: Uint8Array) => void): void; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer the disposable pattern where we return a handle to unlisten, just feels more ergonomic, no strong opinion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. Left some comments.
One meta comment is that I don't feel like I have a good grasp on how we deal with errors, logging is fine for observability, but it doesn't allow the consumer to handle things or at least receive a signal that things are absolutely broken. Maybe downstream from that, still feels like we can be asserting more and be less forgiving with undefined states.
parsed, | ||
)}`, | ||
); | ||
return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, seems like we have a ton of clean up here that we're not doing? Should we be terminating the connection after we send?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or is the idea that there's a recovery path here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hm yeah idea is that client might send the proper message at some point in the future, though maybe that's bad anyways and we should just close the conn?
} | ||
|
||
addErrorListener(cb: (err: Error) => void): void { | ||
this.sock.on('error', cb); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe that's only for the actual net.Server
itself, sock is net.Socket
so it will call both close
and error
transport/transport.ts
Outdated
throw new Error( | ||
`${this.clientId} -- connection to ${to} failed after ${attempt} attempts (${err}), giving up`, | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should probably log this. Also serializing err
here might be painful to read or get good information from.
log?.warn( | ||
`${this.clientId} -- connection to ${to} failed (${err}), trying again in ${backoffMs}ms`, | ||
); | ||
setTimeout(() => this.connect(to, attempt + 1), backoffMs); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
any checks we need to do before blindly calling this.connect
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nope, this.connect
maintains its own invariants!
Why
Having a pre-session handshake to exchange information is useful! Currently, we do this implicitly on the first message of the connection but explicit good 👍
What changed