Select the region closest to you. Mine defaulted to Ohio.
Search for “EC2”.
Choose Launch Instance.
Give your instance a name, like “pds”.
Under “Application and OS Images” choose Ubuntu.
Under “Amazon Machine Image (AMI)” choose Ubuntu 22.04 (per current version of PDS README)
Under “Architecture” choose 64-bit (x86) to stay in the free tier.
Under “Instance type” choose t2.micro
Under “Key pair (login)” click on Create new key pair
Give your key pair a name, like “pds-login”.
Choose ED25519 for the key pair type.
Choose .pem if you are on a Linux, macOS, or Windows with OpenSSH. If you use PuTTY on Windows, choose .ppk
Click Create key pair
Save the file on your machine for later use.
Keep Allow SSH traffic from checked.
Check Allow HTTPS traffic from the internet.
Check Allow HTTP traffic from the internet.
Under “Configure storage” change the number of GiB to 20 (per current version of PDS README)
Click Launch Instance
Setting up DNS
I have a domain (tpaulshippy.com) that is already hosted elsewhere. I would like my pds server to be at pds.tpaulshippy.com so I opened my web host and entered the following settings:
A Records
Domain name: pds.tpaulshippy.com IP Address: 35.90.227.79 (the Public IPv4 address of my EC2 instance) TTL: 3600
Domain name: *.pds.tpaulshippy.com IP Address: 35.90.227.79 (the Public IPv4 address of my EC2 instance) TTL: 3600
My web host did not easily allow me to add the *.pds.tpaulshippy.com DNS entry. So when I connected to my server, it showed “Invalid Handle” as my profile. But I could still browse around and see content.
I ended up switching my name servers to my domain registrar which does support wildcards on subdomains. After quite a bit of waiting for DNS propogation, I got it working.
In preparation for a talk I would like to give at Desert Code Camp I am adding a React Native front end to my simple counting app built in rails. I would like to provide the same real-time capabilities in my React Native version as I have in my rails front-end. In order to do this, I need to find a way to open a web socket connection between my React Native app and my rails back end. I think the best way to approach this problem is to understand how the web socket connection in my rails front-end works and then see how I can port it over to React Native.
Let’s start by taking a look at the network tab when I load the page.
I see a websocket connection to ws://localhost:3000/cable
Now if I search (cmd-f) for “/cable” I see that this connection is setup by the javascript with the name starting with turbo.min
This javascript does not look like the easiest to understand just by looking at it (somewhat minified). So I will ask Leo for a simple set of code to open a websocket connection in javascript. Here’s what Leo gave me:
Now my guess is that this will not work directly without some headers that authenticate the request, but I will give it a try. I create an html page with the above script, replacing example.com/ws with localhost:3000/cable and here’s what I get:
I’m not seeing the data I expect, so I need to dig further into what kind of websocket connection is being created by Turbo. After scanning through the turbo javascript a bit more, I notice that the websocket is opened with something called a “protocol.” This can also be seen on the working cable connection in the network tab looking at the headers:
The protocol in question is called actioncable-v1-json so I place that in my test html page and try again. Now my first line of script looks like this:
const webSocket = new WebSocket("ws://localhost:3000/cable", { protocol: 'actioncable-v1-json' });
Now when I open my test page, I get nothing. No websocket called cable at all. I look at my console and see this:
Uncaught DOMException: Failed to construct 'WebSocket': The subprotocol '[object Object]' is invalid.
I decide to search for the WebSocket documentation and learn that Leo has steered me wrong. According to MDN I need to provide the protocols as a string or array of strings, not an object with a property of protocol. So I change the line to this:
const webSocket = new WebSocket("ws://localhost:3000/cable", "actioncable-v1-json");
Now I’m seeing the websocket called cable again and I see the Sec-Websocket-Protocol header under Request headers in my network tab. But I’m still not seeing any data, and I notice in my console that I have two errors:
That first error makes me think AI steered me wrong again, so I look at the MDN documentation and indeed, there is no “connect” method. It looks like the WebSocket should automatically connect when I create it. So I remove that line. Ok, after refresh I just have the “WebSocket connection to … failed” error. I think I will need to provide some auth headers somehow. When I compare the working one to the broken one, the main header that stands out to me is “Cookie.” I’m going to try providing that header and see if it will work.
How do I add a header to my WebSocket? I no longer trust Leo on web sockets, so I just Google it with Bing on Brave like the good ol’ days. The second answer to this stackoverflow question gives me a way to make it happen. I try adding document.cookie = followed by the _counting_session cookie from my working page.
At first, it didn’t work. I did a few more searches and then decided to try something. I had been opening my test html file directly from my file system. What if the browser doesn’t send cookies that way? I don’t think it does. When I moved my file into the public folder of my rails app and then opened it from http://localhost:3000/testsocket.html the cookies were set properly and I was able to see ping messages.
What I didn’t see, however, was the data from my rails app. Comparing the working version to the broken one, I see that the working channel has a message sent that “subscribes” to the turbo stream.
So I replicate this message using this javascript:
Just in case you didn’t read that carefully, that script contains an identifier as stringified JSON wrapped inside stringified JSON sent to the websocket when the websocket opens.
Now that I get the information flowing, I notice one more thing. The information sent via this websocket is the HTML that turbo is sending to the page based on what changed.
While this works fine in my rails app, it won’t really be ideal for my React Native as it won’t have HTML at all.
In order to make this work on React Native, I will need to figure out the following:
How to get the session cookie to authenticate the initial websocket call.
How to get the signed stream name to subscribe to the Turbo Stream.
How to use the information sent by rails to update my React Native app.
Here’s what I’m thinking I will end up with for each of these:
Use a custom endpoint authenticated with a signed JWT issued at login to provide the session cookie.
Use a custom endpoint authenticated with a signed JWT issued at login to provide the signed stream name.
Create a custom ActionCable stream for the React Native front end that provides the information in JSON form.
Part 2 – Authenticating React Native to Rails
I did a little more testing on what I did yesterday, and it looks like the cookie is actually not necessary for opening the websocket to rails. The only reason it wasn’t working initially appears to be because I was running from an html file on my file system rather than running from a domain. It does not even have to be run from the same domain. I was able to host my html test file from localhost and open a websocket to a deployed instance of my app and it worked just fine without a cookie. This eliminates #1 of what I needed at the end of Part 1.
While I intended to support Google sign-in with my react native app (like I have with my rails app) after looking over the steps required I decided it was not worth my time just for a demonstration app. I will just use basic username/password auth.
Next, I need my rails app to send JSON when the data relevant to my user changes. I will start by looking to see if I can use the built in turbo broadcast and just customize the format. I googled “customize turbo broadcast stream” and looked at the first thing the Brave search engine referenced, which was the Turbo Handbook. It contains a link to the Broadcastable concern in Turbo. Looking at that file, I see the example below:
I’m wondering if I can use a custom partial to return JSON instead of HTML.
I fire up my Visual Studio Code and start my react native app to reorient myself since it has been a few weeks. In order to avoid using my phone and the Expo app, I navigate to my counting-rn folder and use this command to install react-native-web so I can run the react app in my browser:
Then I run npx expo start and hit W. My browser opens up to http://localhost:8081/ and I am able to see my login interface I created. I enter my credentials and hit Login. Then I realize that I have not started my rails app, so I open another terminal and run bin/dev from my root folder. I try the Login button again and realize that I need to use localhost as my base URL. So I change this in client.js. Then I try again. I get a CORS error because I’m now trying to use my browser. So I install the gem rack-cors in my bundle and add this block to my rails app in the config/environments/development.rb file:
config.middleware.insert_before 0, Rack::Cors do
allow do
origins 'localhost:8081'
resource(
'*',
headers: :any,
methods: [:get, :patch, :put, :delete, :post, :options]
)
end
end
Then I realize that the response from my rails app, hosted on localhost:3000 will not include cookies when the request is made from a browser that is on localhost:8081 anyway, so I give up on this attempt to use react-native-web and go back to opening Expo on my phone. I have to go back and restart my rails app using the command rails s -b 0.0.0.0 instead of bin/dev so that the port is open on my machine’s IP address.
I add the following to my react app to open the websocket:
The next step is to figure out how to get the signed stream name when I login. Turns out this is pretty simple. The following line of ruby gets the stream name:
Now, this is not currently secured to my user’s counters, but I will handle that later. The stream is now successfully showing messages in my react console whenever the data changes in my counters on my rails app. But it is still in HTML form. So I go back to that Broadcastable idea and try adding this to my model:
After experimenting for a while in my rails app, I realize that what I need is not to broadcast to a partial, but rather to broadcast with a template. So I add this to my model:
after_update_commit :update_clients
def update_clients
broadcast_replace_to "counters_json", template: "counters/_counter_data"
end
And I create a partial called _counter_data.erb with this:
<%= counter.to_json %>
Then I change my line that returns the stream name to say this:
I use Bitwarden as my password manager. It is open source, battle tested, and secure. But I realized recently that it doesn’t recognize a subdomain as a separate website to which I can login. One of the applications I use daily has many instances that are hosted on subdomains and each instance has its own username and password. When I need to access an instance, I have to navigate to the URL and then manually select the right option from a long list in my Bitwarden plugin for Brave to autofill my username and password. This got me thinking – I wonder if Bitwarden has an option to handle this situation.
Turns out the Bitwarden team has solved this with a feature. By changing my default URI match detection option to “Host” I get the behavior I was hoping for. The plugin matches the right instance by subdomain and provides me a quick way to fill in my username and password.
I am setting up some scripts for using terraform to deploy a node project to AWS and when I execute the commands from the root folder, they do not work. They must be executed from the folder that contains the .tf files. But I am not sure how to do this in my package.json file. The scripts property looks like this:
"scripts":Â {
        "start": "node server.js",
...
"deploy": "terraform apply" <-- must be run from subfolder
}
Thanks to the answer provided by eljefedelrodeodeljefe, I learned that you simply have to include “cd FOLDER_NAME &&” before your script and this works across most platforms. So in my case, this looks like the following:
"scripts":Â {
        "start": "node server.js",
...
"deploy": "cd infrastructure && terraform apply" <-- must be run from subfolder
}
One nice thing is that this approach is consistent with the syntax used in a Makefile for a Python project I have recently worked with.
I am creating my first AWS Lambda function in Python from scratch. My function contains async functions, so I declared my handler with the async keyword. But when I deployed and smoke tested in AWS, I received the following error:
{ "errorMessage": "Unable to marshal response: Object of type coroutine is not JSON serializable", "errorType": "Runtime.MarshalError" }
Apparently AWS Lambda does not support async handler functions in Python. So you are required to call your asynchronous code from a synchronous handler function using this line of code:
My dad has a new phone since we recently switched back to Total Wireless from Sprint. It is another Android phone so most things are the same but there is one feature missing. He cannot drag and drop appointments on his Google calendar to different days or times.
My doctor informed me at my last annual physical that my good cholesterol is too low and my bad and total cholesterol are too high. I knew this from past tests but he urged me to take action to improve my levels. I also know that this is somewhat genetic because my vegetarian marathon running Dad also has the same problem.
My doctor recommended exercise and dietary changes. Though I have not increased my physical activity as much as I should, I did improve my diet. Based on a suggestion from a friend at church and with my doctor’s support, I also agreed to try a supplement called red yeast rice that has similar effects as prescription statins to see if that would help. This was about six months ago and I’m wondering how often it makes sense to test cholesterol levels in my blood.
My first search only returned articles recommending testing every five years or in certain cases annually, or as prescribed by a doctor. But I wanted to know how often I can test to see improvement based on dietary and supplement changes. So I was more specific in my second search. The answer was in line with my doctor’s suggestion.
I learned that taking this test as often as three to six months makes sense to see if changes have had the desired effect, so I have a blood test scheduled for this week.
I also learned that you can order this kind of routine blood test directly from companies like Sonora Quest without having to go through your physician or insurance and it is very affordable ($28).
I am building a simple model class in Typescript/Javascript and was wondering if there was a shorthand way to avoid having to explicitly set each property name based on the constructor arguments.
I need to provide instructions in a project on which folders and subfolders need to exist before the code will run locally. The required folder is three levels deep, and I want a quick way to create the full directory tree.
Normally I work in SQL Server when I am dealing with relational data but on my current project one of our primary systems uses Oracle as its back end. In order to quickly generate a list of column names for use in an access request, I need to interrogate the table metadata and I cannot recall the way to do this on Oracle.