SignalR Deep Dive: Building Servers - David Fowler & Damian Edwards

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello hello testing okay good sorry for the slight delay we had a network connectivity issue but we are on now so well I am Damian this is David Fowler David yeah we are from the a spinet team at Microsoft today we're gonna do a talk on signal are a little bit different to the talks with are in the past we're kind of challenging ourselves what Dave is challenging himself really I've got the easy job to do something that we're not particularly familiar with which it'll be fun but it's we're gonna use it as a teaching and learning exercise to hopefully let you walk away with a bit more information about how signal hour works under the covers and what has driven some of the recent expansion in how you can use signal I was just kind of cool especially in these new sort of cloud focused scenarios so very quick refresh on what signal are is I'm assuming I shouldn't assume but does everyone here know what signal is who who is used signal are before excellent okay well we're gonna do a quick refresh because you know it's been what six years now I think we've had a version of signal herb that's been shipped but we've gone through two major revisions we've got the sort of classic signal our phrase Fannett and then the 8-minute core signal our which came out was a year and a half two years eighteen point one point one so what is it well we've got to changed how we talk about it we used to talk about incredibly simple real-time web for net which I think I coined six years ago but now you know we've moved on the industry's a bit different we care about other things and so what is signal are it's a framework for duplic duplex RPC and and streaming between client and server there's lots of other RPC frameworks like we add a G RPC support needs Bennett core three but signal I still has some unique capabilities especially the server push element which you don't get from things like G RPC which is why it's still around that's the real-time messaging written server server push functionality that I talked about there it also is built on top of a set of unique protocols that really formed the basis of signal art in the original signal there were protocols under the covers but we didn't really talk about them we didn't you know standardized them that we didn't really document them they were just an implementation detail of the ACE P net signal our framework now that we're in more of a heterogeneous sort of embracing the heterogeneous world on the asp net team and we have a sure and we have services all the type of things we want Sigma to work with as many things as possible and so we do have a product a couple of protocols will talk about that and that's what really allows signaler to work these days then we have this service support for client addressing and grouping and that's one of those things that really extends signal are beyond your typical RPC framework right you have the ability to say send a message to this individual client or to group a series of clients into a group that you call them and send them a message you don't get that with a typical point-to-point RPC framework so very quick demo here's you know classic signal our app the Charter app chat are all signal apps have to have their last Val remove in order to make them a signal or app so I'm going to boot this one up and it just looks like the standard sort of chat app you would have seen we demo for signaler for awhile if your browser is downloading a proxy script which I'm very happy to so I can type in here and hit Send and it sends and comes back from the server all the type of normal stuff that you would see and I've got this other button over here Stream which utilizes a new feature in signal area nice Burnett core and I can click that and the server is streaming information down to me it's going to count up to 10 in this case now we were able to do things like this before in Sigma but because of a spinet core and we have some new browser output window stuck there that's super interesting I'm using David's laptop so if I'm feel like I'm clunking around a bit that's why so let's have a look at the server code so we can all remember and refresh yourselves what this looks like here's the really simple part right the send message on the server is just in a hub I'd turn around say clients dot all that send async and that's all I have to do the stream one is the new one so I'm now taking advantage of you have turned off tap having me would like a terrorist all right that's why I'm struggling so much we're using the C sharp 8i async enumerable or async streams feature in order to very simply allow a client to call the server and then us stream information back with a beautiful awaiting yielding full loop right there like doing that type of stuff previously required you to use extra frameworks or other type of primitives now that stuff is all kind of built in what does it look like in the client it's all pretty straightforward as long as you're happy and comfortable doing JavaScript that is the wrong file that's the C sharp file so you know we've seen this type of stuff before I've got a bunch of JavaScript I create a connection up here on line 35 I'm configuring some logging so we can see some stuff take place I'm gonna grab my chat form it's wire up an event listener check some validity I actually used like html5 validation and stuff in here which is kind of cool and then I go ahead and they do some Dom stuff like this is all very very standard type of stuff that you would have seen when doing any type of client development I'm not using any frameworks this is just bare-bones to sort of see how this stuff works so that's our super quick refresher on how signaler works that's all we really need to get back to in our level of understanding to understand what we're going to do the next so we've all seen in the past how signaler supports multiple clients I showed you the JavaScript client just there we also support different transports so I'm using WebSockets but as we've had forever we fall back to other transports like service and events and long polling in the cases that we can't do that and we ship a bunch of client SDKs we ship the JavaScript SDK the dotnet SDK the Java SDK there is a swift SDK that's third-party there's a Python SDK and we are currently writing a C++ SDK so we've got all this nice support on the client and our transport so what is it that makes that possible well I mentioned it before we have these protocols so this flexibility is enabled by two layers we have a transport protocol layer which as you can imagine it defines the set of rules that say while a client wants to connect to a server over some type of transport ok the default one that you usually use too is HTTP but you can plug in your own transports if you wish to and there's a to respect their you can go up onto our github site you can read the protocol spec to enhance port and then the second layer is the hub protocol and that's the messaging protocol that signaler uses to support the fact that the client can call a method on the server and that the server can call methods on the client and that gives you all the message types that you would expect in any type of protocol so for transports we've all seen these type of diagrams before a client connects to the server with long polling and then the server is going to wait for an event to take place in that response back and then the client will send another request the server sent events was one of our fallback transports as well the serve the client will send a request to the server the server turns around and then pumps messages down over that event source object stream back to the client and we can get messages that way WebSockets is the one that we really want to use right if we're in the browser we do a WebSocket request to the server the server says yep that sounds great let me ever send you back a 101 and we'll switch protocols and then we can just happily send messages to each other over that existing TCP connection wonderful the very first request that gets sent is a negotiate request before any of the messages start flowing the quiet and the server have to agree on what transport they're going to use and what protocol our messaging protocol they're going to use and so we send up a negotiate request post some endpoint with a negotiate path and optionally sending a negotiate version and then the client the server will respond with the response with a bunch of metadata like a connection token and an ID what version are we can negotiating with and then a list of transports of the server supports okay then the client can use that information then to actually make a connection to the server here are the types of messages that are in our messaging protocol so this is all the types of messages that are required for a server to support a client talking to it with hubs you don't need to know these you can go to github and read the spec but if you're going to build a server like we're going to today you'll need to understand these different type of messages so that you can set up a compliance server so clients can connect you so why don't we build a server because I mean we can show slides all day but I want David not to on stage so I'm gonna make him write a server in something other than a dotnet language Mario you're gonna use go yeah add a programming go right nope okay does any want to hear it no goal who knows go does anyone know so no one's gonna be able to call him out anything anyone can do that it's like you guys kind of data alright I probably learnt go over the last couple of months I got super annoyed very well but no more than you guys service good alright so let's do a hello world gold just to everyone's feet wet and warm wet warm warm and wet alright let's in the same folder I'll do a make there dry run this is fully open BS code yeah code supports every language pretty much pretty much on the planet right so I'll type in the main go here here's my empty file right easy suffer I'll create a package is like a an assembly boundary basically package main here's my main function isn't doing very much right now I'm gonna print hello world so fmt print lying hello world pretty simple so import her so first dotnet developers imports relate using I want to import namespace okay if MT is the package name okay FME has a packet method called print' light on it I'm calling print and I'm printing hello world pretty simple right on the shell I can run go run main I should print hello world right that was quite awful awesome all right we go developers Oh excellent yeah if nothing else walk out today see you've now know how to do hello world and go alright so that was that was lame okay let's do hello world HTTP so I can connect to that with signal on that right no okay so there's a package called HTTP in goal framework and go DCL understand HTTP package where i can call methods like listen and serve which will listen on a on a port and address i can say listen on localhost 8080 five because that's very specific for a reason haha I can so far this is nothing right it's actually listened to add code for a specific end point okay so I want a handle handle funk slash and I wanted to return hello world I'm gonna do an anonymous function okay and there's no type in for single yeah so I have to actually remember this it is w is a HTTP dot works response writer and request is a pointer pointer of HTTP you don't request not read request request alright good so far all right now I'm gonna print hello world so write W dot right this should be like that they should probably not be there all right better write hello world and it won't work because this is a a byte array this plus a bite area and I'm passing it or a byte slice and I'm passing it a string string right but in go stranger bytes I can just cast it I should just work Oh constitutes all wait other way around buttery right I can cast this to a byte array I didn't go everything is backwards so this is an array of bytes well yeah I was like even your application of my lambda backwards to what I'm used to is its forwards because you your English you're saying W is a response writer request is a pointer to replace okay so it's like VB all over again oh I mean I mean yeah so if I hit port 80 85 alive okay so we've got two hello world mr. Ringo we're closer to connecting the signal a client at this point yeah I have an ace to the end point alright first step is to get your application into Matt's kitchen so you wrote this thing called chatter yes and it was in a folder called chatter and it's supposed to call it the root yes I'm gonna copy all of it over to here okay can I have your entire yeah hey you got you got all my stuff thing let's rename this to index okay and then tell go to serve stomach falls from the group okay so I can do by the way I have a script I'm gonna copy and pitch me at some point I'm just like going for my brain right now okay so handle slash and I want to handle all files so file server and AC Peeta der I'm saying hand serve files from this folder so here's that folder but the route the file server method is returning a handler yep basically and then that's been possible handle takes a path and a handler a Tyler is an interface that has a method called serve yep sir takes me requests and a response you can write though it's like out requests it's like a request handler in the network middleware and file server implements the the serve interface yep and it gives you a way to specify a directory to serve files from make sense right so now I should run this again and I should see my Damian is beautiful you went to see boots way too much time trying to network hey it's got to be pretty for the people but Ingo if I hit the actual network networking start annoys hit look at the console there's lots of errors yeah so it requested the negotiate endpoint and then I said couldn't find it makes sense right I don't have negotiate endpoint so we're basically at the first point my JavaScript code is running I showed you before signal is trying to make a connection making the device sheet request yep ending a 404 because all you've done so far is write an HTML page yeah toppy my HTML page yes copy sorry I'm building on your and your previous the first step in getting the protocol to work if you negotiate endpoint that's correct so looking at the full protocol to here is the actual link to the website that has our protocol description I had described with a transport protocol has to be full duplex has to be binary safe has to be tech safe describes didn't ago she endpoint the responses for version 1 versus version 0 so we're gonna implement version 0 response to that okay I'm Lizzy who's ever like implemented a protocol before like look there at the read an IRC or read some protocol and they've written code to implement it like a few hey that's a few people that's good ok so I want more clients we want something fun to do go and try and implement ours and then give us feedback it is if it's any good like maybe we need to improve our protocol it's perfect it's perfect yeah okay I will let them be the judge of that based on how well you go in the next half an hour so I'm going to create a function called map hub to map my hub and to not write the thing in Reverse it's a path or a pathway the string okay okay path in the string I need to handle the negotiate method first so time to start a copypasta okay negotiate always goes to slash negotiate that's hard-coded it is okay I believe I have this thing in snippet all right hi chichi okay map hub pretty simple let's do much here's negotiate I need to copy the actual struck so in go strikes or battle strikes verify your types the live on the stack so I'm declaring two straps here that will throw my negotiate response okay and these tags over here are the attributes so these are like Jason name is transport lowercase T and Jason name here is also lowercase transport formats and then you can also add things like I want to omit this feel that if it's no for example so this is basically an attribute a c-sharp so thing this has like this other stuff that can be read out reflection time got it got it it's just matter they have yeah a special comment yep it's pretty gross I love go tell us what you really think that's fine nobody have to actually like handle the ghost yet method so map hub will hit the string in to the path the path bit of the actual signaler connection I'll make the Sigma hub chat is the actual hub okay and here's my negotiate handler which is like slash chat slash negotiate right where this is going if you look at the actual error it should have said /type /annot she ate right here yep okay got it is it alright so let's copy-paste this negotiate handler so we can have a time to explain it alright so what did we just do we copied a bunch of things from my snippets the first thing is expressive post not a get or a put her up if your not post return of 400 it's a bad client plants doing bad things for any particular reason we want to post and certificate no okay alright that's fine I think it was because security you want to plan for hanging a body at some point okay I think we had a body in the first version and we removed it okay reasons the shiny can be any anything we generate a random crypto hash for security reasons the connection ID yep okay so the ID this way well this what identify your connections for future use easily I want to talk to that connection so this is ID and actually Jen from the server-side the protocol doesn't specify the format condoning anything it's just an opaque string that's right okay so get actually ID we'll just basics for encode a randomly generated by Turay okay this is this is the goal the goal version of new random new crypto random like generate random bytes okay this is before encode divider into a string and then we send JSON response that map to this truck so this is this is the equivalent of doing new negotiate response setting properties set fields and then setting values and this returning okay a giant rate make sense right this is good so far simple simple all right let's see why our server doesn't know so I'm not having to do a ten point I'll be run go and in EDM does anyone here use edge iam I mean edge new edge new edge are we supposed to call it we should have looked at the marketing material before he can GM make it a thing edgy edgy you krej is the other one at hawk I just so bad though okay all right so I see more success this time perfect okay more white less red so negotiate responded with a beautiful jason response we can see it got responded here transport WebSockets that's for a formats text binary transfer form is basically let you know if the transport supports text or binary means pretty obvious here so that's also new in a snit course again ours we now support binary message types and so the transport has to say yes I can do binary I mean when you have that because server-sent events did not support binary so we have to be able to tell you whether we do it or not yeah but it tried to connect to the chat endpoint with the WebSocket hand request and it get before four okay so renegotiate now the next step is the client wants to say yep I'm ready to send you a WebSocket because you said I could use WebSockets yep so it created a WebSocket connection but that horribly failed because you haven't written okay okay okay so let's add some more code now so let's kill the server all right copy pasta in my public I'm gonna add some code to handle a website for the connection is that built into the HTTP package you were using already they have a WebSocket thing it is so there is a WebSocket package as well that is separate okay yeah after you recommend using a third party package because it's a one built in is probably not good oh okay you always in the built in one yeah of course so so I added a handler for the chat the hub endpoint okay and let's look at the high-level returns a higher instance that implements the the handler interface yep gives me about for a connection jacket actually get stuff from the request and response from so if you had negotiated from the client side so the client can do in the go she ate get lady back and then connect with that idea to WebSockets okay so I've have an ID I'm gonna send that up with my right socket connection and pass the other a string in the query string yep and then the server I'm assuming that would usually validate that yes that was the idea I create for you this is also a ways they're gonna require sticky sessions in core because you have to have had the ID come from this server it's tight full staple I'm not innocent okay that request for some period of time yes there's also a feature in Sigma Arbor you can do under gonna go she ate list connection you can connect with an endpoint directly from the client side to by plug if and will just work so why did we bother with doing in the guys ship is by default in the go she is because it wants to support flow them out to the other transports at the surprise if the client doesn't know where it's gonna run okay the client has to be able to negotiate about the other transport okay so the modern signal a server does support doing like a single request connection right thing well you don't have to negotiate first if you just both Yolo I'm gonna use WebSockets can I know because I know it'll work where do I get my ID from if I don't negotiate so the color so the code says get ad from the query string if it's empty just gen1 oh okay cool all right all good in the client-side there's an option called skip negotiate if you make it true it just does the actual dirt nice okay but if you can figure skating ago you have to say WebSockets only fair enough so you can't do skip negotiate suckers is the only one that supports a direct connection so you need to correlate with an ID that's right okay so here's our up luck it handily no no we should be good to go all right this should work mmm all right so you have a WebSocket endpoint now so we would expect to see the WebSocket request succeed less read more white okay yeah this is less read okay so it can be WebSockets it got was happy it sent the handshake the there's a handshake that goes from client to server okay it chose JSON protocol because that's the default protocol then it died completely because the goal server actually wants you to keep this function around until the socket is dead so if it doesn't nothing it'll just kill the whole cache in amino so you have to start reading from a from the actual socket once you go would do that packin action so I have to write a for loop in here so let's do I'll just keep copy pasting to this probably easier I know right so here's the hash a request let me get from the client side oh oh okay so the socket was established yep and the very next step is someone's gonna send the message that's right which end is sending the message the client the client will send a special message object message right that's a signal our message right and that's part of our transport spec or part of the hub okay fantastic so we went from from transport protocol spec right we really went from not having action to having one once we have one you flip into the hub protocols but now we're in the hub protocol was doing hubs and the hop work lies about invocations okay and both dreamers have to negotiate the actual transport hub protocol right behind shakes for the very first thing in the hub protocol is the highest request okay god quiet stands the hand she's saying I can do Jason version one and the server says no stop or yes that's cool okay and then it sends a handshake response if we if we very temporarily print out what happened let's just do that so then go there's no well true there's no while loops there's no do well there's no for you oh like an empty for there's a fork there's just one big one the type yeah those way okay let's locate that I says I'm gonna read a message off the WebSocket off the wire I'll declare a data array of bytes slice of bytes receive data and then error handling go is kind of jank see you end up having to write code like this a lot get a thing that has an error there's no exception it's nothing throws and blows up in your face it's kind of nice okay also when you save go format rather than this format your code just destroys this very opinion it's good it's good it's good why is it doing that oh it's killing me what huh okay hold on there's something wrong here you've got if at the end instead of just oh it's not equal to AH way okay good let me just print this so FMT that print the print line okay so you're receiving a message and if there was an error then you print it's a break yep I break out okay and then I'm gonna print the actual data from the client server so whenever I receive a print on the console okay so I received then I'll just cast with shrink is that's cool assume all bytes or strings is I'll be doing codings I expect to see some wing-dings yeah Jason should work alright so at this point I can just refresh she got the same right but there's no more white that's interesting so the server received the protocol there's a handshake a football Jason version one we're good to go so now we should part the protocol assume is good because this code is perfect so this is a handshake doesn't the climb expect you to shake back they respond yeah isn't that the whole point of a handshake like right now I've done this I know it's kind of embarrassing I guess so we're gonna copy this giant process handshake function did fail eventually yeah oh yeah why did it so okay so it time to time down yeah hey so the client I did this all right I guess no one's there all right doorbell no one's home no one's home tap out okay I'm gonna copy this process handshake function which very naively parses the handshake take one protocol let's actually look at the protocol in a different browser I love Ejim but this is a bug this is bug in the new Chrome diet verifiably the actual chromium team so it's not a giant fault oh really yeah weird WebSocket inspector only shows one frame Oh oops so as long as what you want is in the first message you fine good to go okay I'm on I'm on the bleeding edge bits of Aegean that's why it didn't work it was miss river still running thread this again so you can actually see the data being sent over the WebSocket connection connection there it is there it is I guess when you sent one thing but see this this block this super strange blood that's my wingding you came through it's awesome so every single message in the Jason protocol is permitted by the it's called a record separator what's a record separator record separate yeah it's ASCII cool of 30 okay we chose it because we needed to have a protocol that wasn't bound to a specific transport we could have said every single message and Ziggler is bounced to the WebSocket message that would be easier I see but to make it hard for ourselves we want to have our own format I can left across mobile transports okay so if you're on TCP there's no framing so how do you find the actual end of the message if you don't have framing need to know this is the end this is the end of a signal a message yeah which means you could have more than one frame that happen but is it a full message until you see this actual do you want to use character turns or line see it had to be Jason say you can't put this in Jason I'd be fun to one then you can open it isn't okay all right so let's press the handshake so here's a response here's a night a parting because we're super night we're gonna assume that whatever gets sent that the first thing that gets sent is the actual protocol the highest rate request I mean why even is that actually naive or is that for perfectly legitimate not what you would expect the client set a single by our time oh I see it would break but who does that who does that it would do that yeah a malicious client may be okay for this code assumes that the thing I got have a full method I had a full message because I'm lazy so I got I see I get it I get a payload and then I look for the 30 which is the actual record separator okay I slice here's a slice operation they can just like say you know get in this an end so I unmarshal is deserialize so I allocate a struct ID serialize the payload into that struct and if there was an error it's it's the words you realize and deserialize a.net ism what does everyone say that I think on Java this is decirles if Java oh yeah cuz I'm Marshall sounds I've seen part different stringify Marshall unmarshal it sounds more level it's something more like I'm quoting sounds scared I'm quoting super hard I'm muscles Marshall Marshall unmarshal the protocol isn't Jason return an error response to the clients are you okay and to me is Jason oh we're all good okay so I'm going to run in the handshake response okay yep so I'm gonna run this first I'm just say error equals process presence handshake WebSockets in the handshake it's good if like every piece of gold and planet if air is Michael to nil just awful just Oh return and print because in case I want to see the ER yes Prince it okay okay so this should work now we should have way less read so in theory now we'll be able to leave it open and a one time out it'll just we've done our handshake and now we're waiting for something else to happen how many seconds do we have to wait to be guaranteed their success oh okay serve a handshake complete all right okay handshakes good we're done okay so can i all right make it fail again where do something else will suck it suck it suck it there it is okay uh-huh no I'm my head you might see from that's the blood by the way see it returns whispering means client going to server and red is server back yep right okay and so the server sent back an empty Jason object yep sure is the handshake being completed yep okay oh what's that interesting so the client just tried to like do something yeah what is it doing let's find out so when you're lost you just search for type also we're back in the spec okay Type six it's a pain a ping it's the client and server send pings back and forth to make sure they the other parties okay okay they're right this was the client because it was green yeah it was gonna quietly I think of the server side okay and if we're lucky they sent two things whoo and at some point it gets angry and says you know what I'm not pinging me you're offline okay so signal are includes a ping-pong kind of thing basically apologies pink just pings but is their only client to server or just the server sender ping as well in a good server not your server yeah and the good server says penis both directions okay and so the client is basically trying to make sure that the connection is actually alive be great you never trust what your connection API is telling you go through a tunnel of your connection you go up on a plane yep you fly through our knowledge fly through a tunnel a black hole okay I think we are working black hole sorry once the two pings basically don't get a reply the client says nope this connection is not good isn't just Pink's it's any messages and emails when you get sent if things haven't been sent in that time for okay okay all right so we need to get the server to respond mm pink all right we need to add our own pinging let's do that let's do that let's do that there's things here's my super fancy ping logic what what's the ping timer what's the timing it expects I mean seconds some protocols specify if in the code summer no okay the client decides went to to diabase on a threshold I think our default is like if you haven't seen it at least two pings in like 30 seconds okay 30 seconds that's the default yeah we figure it yeah you can we tried more aggressive numbers and it kind of broke people so we kind of went conservative by default said so it dies at some point but it's not super aggressive okay you can tweak it to be whatever you want on the client side so here's a ping er so in.net you'd create a new timer new timer has a callback that gets called every whatever seconds you passed into it in the call bot he would just like write doing something there right right super simple ish until you learn how it works right this is the goal version you create ticker and and go there there aren't that many primitives so the pattern you see a lot is channels so a challenge is a basically think of it as an is ignorable you can actually read from or write in - okay so I create ticker I'm gonna run every 10 seconds and I made a channel of bull just don't ask why this is here yet here's an infinite loop and it says whenever the ticker fires run this callback so I'm casting over the actual channel firing are done being sent okay they fire an anonymous coroutine in line this actually this this is TAS not run combat yeah this is tango okay I'm ticker is basically this is basically a a weight for each have you guys seen the icing and durable powdered in c-sharp yeah well I showed it in the chat oh yeah wait for each is equal weight for each tick and ticker okay right this code does that okay all right take your word for it cuz no one in here knows guys it's perfect we can come you all right at the end take it out stop and I'm gonna write a bull into the done channel ah she's super super janky synthetics you're putting something into the channel that's why you're doing some right yeah okay so it's a challenge on the on this side you're reading from it this side being what side the there right there looking at it this for right I'm putting true into done okay pushing it in like forcing it in all right so now this should give me a stable connection a stable one thing so this should not timeout okay let's look at crome and just stare for like half an hour maybe deja vu I think last year we had a signal a demo and recall that we spent a lot of time waiting for something to go wrong middle at all it's because oh okay there we go all right oh okay two pink spin but one of the first one was red yeah that mean the server was sending one day ah every ten seconds the service end the pain and every something the client's of thing oh I can't I just got I think you said this before in the punk each side is just sending messages each side is just saying if I don't see anything from the other side in a time period I'm just gonna assume that you nicked off yep okay got it got it alright cool stable let's try you actually use the question oh let's do an invocation okay that didn't work so on the server side we received the invocation but nothing is handling it okay right so the handshake happened sending things back and forth we're stable no and nobody actually handle it so my generation that I wrote defending a message to say please call this method but you're going you're just ignoring it you know what I'm saying cool cool Tori you're throwing it away yeah well the client fail it does hangover alright yeah alright so let's sounds like if it looks like we're close yeah this feels right some more copy and paste a movie done soon all right so we're gonna copy this these two types hug message and how about his implication to the top of the file because that's clean every message and the Jason hub protocol has a type property it tells you what type is being about type six is paying type 4 is whatever I want is implication and then an implication message which is type what is it me for type 1 has a bunch of specific fields like the target which is the method being invoked the implication ID which is an ID so the client can correlate responses from the server-side right so I book with with implication 0 you sent to the server side the server wants to respond with a value the server will say implication zeroes response is this ok then arguments are a bunch of Justin arguments please show method you're calling on spawn so let's finally at the point will be doing the IPC base okay here's our PC okay little let's hustle so here's the man loop I'm gonna copy this codes slash it into right here by implication you want more snippet this one you're printing your message is twice I think now yeah yeah good alright so on receive we find the record separator ASCII code 30 sliced a byte array get the raw hub message deserialize into the actual one that has a type only this is kind of inefficient but it works I get the type if it's one that I know it's an implication so I do it again but using the Raman the full message right a sense sorry so you need to be able to parse to know what type it is you need to know the title copper t eating just to see you read just the type I see you figure out this 1 to 6 I knew parse the actual concrete type based on that number got it I'm excited I just get the invocation and we call it on implication method there's nothing right now right and to make it do something very basic we should actually respond with the completion response and the completion response is in the spec and it's type 3 and it says here is the type 3 which is a completion and the application ID but which I'm completing and it can't have an error or it can't have a result okay but it cannot both failure this is the answer to my a piece equal support a call violation yep okay that's right it can be no if you're avoiding I'm not returning anything okay it can be no it's lawyer forget type of thing not for I forget no no just void this void okay I see it's still a response some response but nothing is in it right so you've got it so here's the invocation and we're going to do a basic completion Act so I'll copy this logic into here this is nothing it's funny this is actually a compiler if you drop a trillion comma oh wow holy all right this shouldn't make the implication return nothing nothing well so back to our protocol test here's a response ah clients happy but nothing happened but I didn't get a message no okay nope so let's make this work note so now we're at the point where the client was able to call like my hub method yep but in my other example the hub method was turning around saying clients all dots end right but we haven't written that part yet and go right and so the clients like yeah I sent a message but now we need to do the pushpot correct so ever needs to push this to all the clients and it's important to know that the protocol doesn't dictate the actual grouping are broadcasting or I send to a client he's just talking about what happens between client and server right so I call a method on the server side the server can decide to return a result yep broadcast everyone broadcast to a group not returnable all I doesn't know nothing no routes or anything it's just like I got a message just know it was in a group due to the protocol right right that soul says also recited for detail that's right so let's make it do so I had this thing to make it reply to wanna connection but maybe we shouldn't make it reply to both all that once this time is short go also does not have a ternary operator you can't just and go say like you can't do question mark you can't do or not equal to no right this doesn't work and go that's unfortunate someone if I do this this is like horrific right okay let's implement reply to one connection that's what happened as the first step so the first step is you're literally just going to turn around and make sure this message is sent to the per to me okay right but it's not in the reply that's right just I'm pushing another man this is an invocation the same pan sent to the server side the client supports implication so I can send them back to the client and invocation saying I'm gonna echo your incoming with an arguments about client side okay so this guy says if target is sent I'm gonna create a replay type one is in location target is sent I'm calling sent on the client side I'm gonna echo the same argument I passed into the actual server side okay it's almost like echo this is why you're really doing an app yep yet go if I run this this should echo it to myself oh wow yeah look claps tough we're doing that half crowed were you doing the heading go guys can you show the traffic yeah were you doing that did you send the the message to the client before you sent the ACK or did you send it after the ACK good question and does it matter before it doesn't matter it doesn't matter okay yeah because the whole thing is like asynchronous is nothing matter that's right okay so oh it went through this guy but didn't go to this this other browser cuz they're not looking at being broadcast right so you did send it to the client before you sent the client the reply from the original message that's right because I can see in the log okay but I can't get that did you see like the order of operations there okay with the client isn't broadcasting so this browser isn't the same as that browser there's no there's no I'm gonna brush each person is chatting with themselves right mhm okay can we make them so they can talk to each other that's right this is fun chat okay where everybody's right this is like when you get shadow band right in Xbox Live so you're talking you everyone else what we're gonna do here is declare a concurrent dictionary equivalent and go which is a sync map so I'm gonna declare a thing to try the clients clients equals to sink top map No I'm gonna pass it by reference we don't want a copy of it okay yeah if you learn girl you have to remember all this stuff see you see sure so ampersand was referenced and the star was a pointer that's right so I need a point of doing that because what they happen if a pathway value yeah and I mutate the object Oh guess what happens okay no one knows it's a copy it's a copy of the object so you wouldn't happen it wouldn't actually I didn't see it okay clients uh store connection ID so I'm mapping in the connection ID I'm storing the ID to the websocket itself so I didn't have a list of WebSockets by D so just a dictionary just a prediction yep and there is the ID and then the actual connection is the value but it stops I'll just client start remove no it's not delete delete' connection ID and then I'll pass this into the invocation of possibly reference okay why it's no make sure I have this be client is this pointer of sync that and right here the syntax is kind of weird get ready for you might be blowing with a bizarre syntax so this and go is a cast it looks bizarre but it's super nice so the value is an object it's like an object oh you can do it in line like left to right right yeah so interface is the equivalent of object this is like an interface wouldn't with anything right and then I'm doing a cast - I plug a connection because I know the value is like much like a connection got it and doing it this way absol it's me dot and keep casting and dotting that link like a C and C sharp requires LIGO wrapping around Renta sees like this or you can do an expose this and the cast this is no generics like you have to pass it through as an object because you can't just you know do nothing to sync maps of T another thing pretty bad okay yeah that's why does it make you feel dirty yeah 100% what is it saying I can't do here cuz you made it Bella this is there a pointer haha alright so we should have a fully working application if I'm not mistaken oh no we don't get it actually it's good enough yeah yeah even I'm your first yeah good so we have two choices we can make streaming work or we could now I do slides and then I just want to reiterate though like we literally took a functional a spinet course signaler app where we use the a spinet course signaler api on the server i use the JavaScript client and then we took the entire client part and then you wrote a hard coded chat server it uses the signaler protocol in go it's not a generic signal a server like if you want to go and add another hub it's not like you just add a type and then call a map method correct right you have a hard-coded server that's built specifically for this chat app but the client just thinks it's a signal server that's right that's pretty cool all right no iswe think I think it's cool you think it's cool I think it's cool yeah well if they're cool it's fun alright so you built a server and go well so there's a bunch of stuff you didn't do yeah because it's just a hard-coded demo right but what happens if like threads occur or whatever like what does that mean it's not thread safe what you did so the pings are running in probably the actual like other nothing is gonna synchronize okay let's lock it right okay I should be locked I see but for the sake of two clients that turns out it's pretty safe okay there's no error handling really had a lot of if statements but you're not doing anything using it with them other than printing into the console there's no grouping so they no because that is very much like I said some part of the protocol the grouping thing is just really part of our server API and our server implementation so I mean you could add that yep but you didn't do it there's no client to server streaming we could do server to Terminal class streaming server the client streaming which should just be another for loop is my guess with a timer that's right yeah so it wouldn't be too hard and there's no concept of cancellations so in sync today the protocol actually supports cancelling an invocation you didn't do that although you know if the client had tried to say cancel this the server just would have gone all right cool then this is frame interleaving what does that mean well if we think about the two layers going on here we've got our transport frames which in this case were WebSockets right so we have a WebSocket each of these orange boxes is a WebSocket frame or message and they can be of different sizes right and this is per transport they all define how they send their messages according to their spec then we have on top of that the hub messages or the hub frames from the hub protocol and they don't necessarily align with the transport frames now this is just like you can have Ethernet frames and then on top of that you can have tcp/ip frames and then on top of that you can have and I'm generalizing so his network wants like you can know afterwards and then you can have HTTP messages on top of that and they don't all line up perfectly like things get chunked and they get correlated according to the rules of the layout now it turns out that doing it from a browser makes it a little easier because WebSockets in browsers when you call right it pretty much guarantees it's always gonna be in one frame gonna help me because I he'll be right there because of how we wrote it how we wrote the client okay so you didn't have to worry about it but as you can see sometimes in the real world in real implementations they don't line up and you have to deal with that so for example I could have a WebSocket transport frame which has a header with a bunch of bytes that mean things and then my actual message payload and then I could have a JSON ping which we saw right type equals six and then this other message could be my non-blocking invocation message and so like you have to deal with that in a real signal a server otherwise it will be horribly unreliable so what about scale out we know we've done lot to talk to about scale out in the past this is a typical diagram you'll end up seeing we have all of our clients here and in order to support more clients we had more servers but then we have the problem of how does client number one talk to client number four when they're on a different server well then you have to add another layer which is the backplane all the way on the right-hand side and then you know the server's all connected the backplane and they can coordinate messages and send them to each we still support that that's all supported today we ship a Redis a backplane implementation I think the only one we ship now yeah that's all good good and well then we also have this great thing now the outer signal our service which David was a big part of architecting and so this provides signal a scale out as a service as a platform service you know you get a subscription and your app connects to it and then you've got scale out but it also doesn't just do the backplane part it offloads the signal or connections from the client out of your application you don't have to worry about having a web socket endpoint in your a spinet core app anymore you'll go out they get handled by the paths by the platform as-a-service okay and then like magic happens that correlates those messages back into your application and that's fantastic for scale because now you've got to scale units you've got your web application with your MVC and your pages and your hub code but all your web sockets are actually connecting over on this other thing and you can scale them independently you're not using up HTTP connection resources on your web app that's all being paid for and scaled separately in the azure signaler service so it relays that client traffic to and from over a couple of web sockets between your application and the service so here's like how your app starts you've got your client that's connecting to your a spinet core app you've got web track traffic going to like pages or MVC views and then you've got your web socket or signaler connections going up to you to your hub right and that's all in one blue box you can only scale the a spinet core app as a unit you can't split those two things apart but then if you deploy it to add your signal or service your app now connects over to the signal server sort of within the data center right over that black two-way arrow that's some dedicated connections between your application on the server side and the ads of signaler service and then the clients sort of gets split personality they go over and connect all the web sockets over to the client endpoint and but they happily keep doing their web traffic over to your ace minute core app which is fantastic and then this is what it looks like when you add more clients they're all connecting their web sockets to the client endpoint on the edge of signalized service you never see them you don't have to worry about them that it all gets taken care of by the signal or service and then you're a spinet core connects to the server end point which is private to you and then you get an in-memory representation of all the clients currently connected to you the signaler co doesn't know any different your hub code doesn't know any different you just say clients don't all dot Send and in memory it goes yeah I've got six clients send those please and then those messages actually go over one of these pipes to the server and then the signaler service is the one that figures out where they go okay and those clients could be connected all over the world you just don't have to worry about it so it completely solves an entire category of problem that is traditionally very very difficult to solve with regards to scaling sockets basically all right and then one of the things that enables is this completely new programming model servlet who's using Azure functions or AWS lamdaur or something like that okay so with a thing like the signaler service you can now build real-time or server push applications without you having an ace pin air core application there's no asp net in this whatsoever there's no app I've deployed there's no traditional signaler server I just have a client in this case it's changing an out of storage blob that fires an event grid event to my as a function which handles the event grid event and it turns around and posts a message via the rest endpoint to the edge of signaler service which then broadcasts whatever on my actual function wants to to all the connected signal our clients and there are people building apps like this today it is actually basically officially supported by Azure functions working in conjunction with the signal or service so could we build that no no yeah so do them so we just went through the whole benefit of being able to offload your WebSocket connections on to a totally different server can we make that work so you know four minutes four minutes so instead of doing it from scratch I'll probably just record a rose I'll show that kind of explain yeah it works right so I I'm going to open an application I wrote that uses okay okay so here's a basic if that core segment application okay another chat app yep but different actually I'm gonna copy it does - yes I didn't try that and the startup plus it's very similar it has this call to add a just ignore that's the only difference right is that my a spinet core app now is saying you signal a but I want you to use the as your signal a service load that's it they were the difference right so I have installed the vanilla roger Sigma SDK okay no tricks up my sleeve nothing crazy I did this because this is the reasons okay I will mention and the chat hub is the same hub right two methods yep send a stream all the people right and I wrote this and if I look at the app settings normally you go to the add report 'l you would create a new subscript and you I'll just ignore service and get a connection string that contains little your secret key and you're like endpoint address okay so like my app that's still going on done that it's Ziggler service endpoint yeah but what if I could just point to the local host I don't say port is this right you're telling the standard as a signal service client where to connect it's a point to my local figma looking at point to you right fake one right so I wrote wanted go for fun it's a fun fun to profit because that's what we do here it is here's my Sigma or my address signal our server so before I show you the code let me run it to make sure it works still works all right Phil - your signal are go run main let go then if I launch this application should connect to that end point and it says connected if I launch I want to scroll probably I can show you the actual thing happening if I go to localhost five dozen which is my yeah attic off your beautiful application but here is the initial negotiate request to my application okay they returned a response that said instead of going to my application go to the Sigma service that's how it works so in negotiating request can actually respond with yeah this is fine but actually what you did negotiate over here instead and this is how right offload those connections over to another service so the Sigma service gives you gives you an access token for this signal or you're gonna hit a mine is hosted local wave security security security security tokens the URL points the client endpoint the server goes to the server end point there's a plan points on the actual goal server my figler server yep do I see there's a documented protocol for the application to service right communication they implement that's on a different github repository somewhere that you can write ok and if I type test this should work right here's my actual service and traffic is actually going to my go application not my main application so if I look higher negotiate happens on the main server on five thousand on five thousand comes back goes to eighty eight eighty seven which is a segment of service ok connects to that server directly with this giant query string yeah and then from then on it's just ignore business just send stuff I can work through that service can you it will will to clients work that's right that's right let's do this so now my age minute core app is still running because it served this incredibly beautiful page that you wrote that's right and but then after that it only handles the negotiate requests the first one and then that reply is no no go and connect your web socket over here and right that's it doesn't really know anything until the service calls are back and says someone hit Send that's right here's the message yep and then the server runs and says your server runs and says yeah ok class let's send all and then that goes back to the service and broadcasts to all the clients even better the service itself is actually understand Sigler it just proxies traffic from the client and point to the server endpoint awesome alright practice lesson we had done just like touch well ok so hopefully we've gotten a good indication about how signal works under the covers today hopefully you can see why the edge of signal service might be a benefit to you if you're trying to run this stuff in scale there's a code available for people good essay will be it will be by the end of the day yes okay well thanks for coming along if you've got any questions you can reach out to both of us on Twitter and have a great conference Cheers [Applause]
Info
Channel: NDC Conferences
Views: 11,344
Rating: undefined out of 5
Keywords: Damian Edwards, David Fowler, SignalR, .NET, JavaScript, ASP.NET, Node.js, NDC, London, 2020
Id: iL9nLAjCPtM
Channel Id: undefined
Length: 59min 1sec (3541 seconds)
Published: Thu Feb 13 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.