Author Archives: purpleblob

Interacting with Eureka from Swift 5

I wanted to get my little Swift console application (developed in the post Creating a console app. in Swift (on Linux)) working with Eureka.

So in the last post I outlined the simple steps to get Eureka up and running in docker. Now let’s combine these posts along with the information from my the post Interacting with Eureka via it’s REST operations and create ourselves a Swift Eureka client.

Before I get started, I have not found the generation of JSON from types or for that matter generating the Dictionary required for JSONSerialization as intuitive as C# (for example). I’m not sure if there’s a better way to do these things, but this code works so it’ll do for now. But if you know a better way please use it.

To start with we’re just going to manually generate our JSON string to match the POST request that we need to tell EUREKA that our application is starting

let json: String = "{" +
  "\"instance\": {" +
    "\"hostName\": \"myhost\"," +
    "\"app\": \"SWIFT-EUREKA\"," +
    "\"vipAddress\": \"myservice\"," +
    "\"secureVipAddress\": \"myservice\"," +
    "\"ipAddr\": \"10.0.0.10\"," +
    "\"status\": \"STARTING\"," +
    "\"port\": {\"$\": \"8080\", \"@enabled\": \"true\"}," +
    "\"securePort\": {\"$\": \"8443\", \"@enabled\": \"true\"}," +
    "\"healthCheckUrl\": \"http://myservice:8080/healthcheck\"," +
    "\"statusPageUrl\": \"http://myservice:8080/status\"," +
    "\"homePageUrl\": \"http://myservice:8080\"," +
    "\"dataCenterInfo\": {" +
      "\"@class\": \"com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo\", " +
      "\"name\": \"MyOwn\"" +
    "}" +
  "}" +
"}"

Hopefully this is fairly obvious (even with all the escaping characters) what we’re doing, but to use this in JSONSerialization.data method is seems we need to convert this string to a Dictionary or Array, so here’s an extension method to convert to a dictionary

extension String {
  func toDictionary() -> [String:AnyObject]? {
    if let data = self.data(using: .utf8) {
      return try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String:AnyObject]
    }
    return nil
  } 
}

There’s zero error handling here – I leave it to the reader to add that.

So using the extension method toDictionary we’ll convert our JSON string into a dictionary which is then passed into the JSONSerialization.data to create a Data object, i.e.

let data = json.toDictionary()
let httpBody = try JSONSerialization.data(withJSONObject: data!, options: [])

Now we’ll create the URL and URLRequest to call the Eureka service

let url = URL(string: "http://192.168.1.1:8761/eureka/apps/swift-eureka")
var request = URLRequest(url: url!)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.httpBody = httpBody
request.timeoutInterval = 20

The rest of the code is the same as Creating a console app. in Swift (on Linux) but for completeness it’s list below in it’s entirety (don’t forget the extension method toDictionary is in some extension file).

import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif

let session = URLSession.shared
let semaphore = DispatchSemaphore(value: 0)

let json: String = "{" +
  "\"instance\": {" +
    "\"hostName\": \"myhost\"," +
    "\"app\": \"SWIFT-EUREKA\"," +
    "\"vipAddress\": \"myservice\"," +
    "\"secureVipAddress\": \"myservice\"," +
    "\"ipAddr\": \"10.0.0.10\"," +
    "\"status\": \"DOWN\"," +
    "\"port\": {\"$\": \"8080\", \"@enabled\": \"true\"}," +
    "\"securePort\": {\"$\": \"8443\", \"@enabled\": \"true\"}," +
    "\"healthCheckUrl\": \"http://myservice:8080/healthcheck\"," +
    "\"statusPageUrl\": \"http://myservice:8080/status\"," +
    "\"homePageUrl\": \"http://myservice:8080\"," +
    "\"dataCenterInfo\": {" +
      "\"@class\": \"com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo\", " +
      "\"name\": \"MyOwn\"" +
    "}" +
  "}" +
"}"

let data = json.toDictionary()
let httpBody = try? JSONSerialization.data(withJSONObject: data!, options: [])

let url = URL(string: "http://192.168.0.88:8761/eureka/apps/swift-eureka")
var request = URLRequest(url: url!)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.httpBody = httpBody
request.timeoutInterval = 20

session.dataTask(with: request) { (data, response, error) in
    let result = String.init(data: data!, encoding: .utf8)
    print(result!)
    semaphore.signal()
}.resume()

semaphore.wait()

At this time I haven’t got a great solution for using types to define our request as the request has some invalid name keys, such as $ and @enabled (again there may be a solution which I’ve not come across yet). To give the reader a starting point, here’s the code I have for turning my EurekaRequest type into a JSON string.

I’ve not included the EurekaRequest so this really just shows a way to convert a type to a JSON string.

let instance = EurekaRequest()
let encoder = JSONEncoder();
// required to stop // becoming \/
encoder.outputFormatting = .withoutEscapingSlashes
let jsonData = try encoder.encode(instance)

// convert to a string
var json = String(data: jsonData, encoding: String.Encoding.utf8)!;

Eureka in Docker

I’ve actually covered this in a previous post, but because it was part of Eureka Server (using Steeltoe) revisited. It didn’t quite stand out when I was searching for it, so let’s recreate here in it’s own post…

Pull the docker image using

docker pull steeltoeoss/eureka-server

Now to run it

docker run --publish 8761:8761 steeltoeoss/eureka-server

This will now be available locally or remotely on port 8761, i.e.

	
http://locahost:8761

Creating a console app. in Swift (on Linux)

The first thing we need to do is use the Swift CLI to generate the project etc. so run

swift package init --type executable

This will generate Sources folder, Tests, the Package.swift and even a README.md and .gitignore.

Now in the previous post we created a simple hello world Vapor REST server, so let’s write the code to call that from our console app.

import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif

let session = URLSession.shared
let url = URL(string: "http://192.168.1.1:8080")

let semaphore = DispatchSemaphore(value: 0)

session.dataTask(with: url!) { (data, response, error) in
    let result = String.init(data: data!, encoding: .utf8)
    print(result!)
    semaphore.signal()
}.resume()

semaphore.wait()

Let’s break down this code…

The first bit of interest is the import. We need FoundationNetworking for the URLSession.shared within the Linux implementation (if I understand correctly) but not in the Mac OS version (I need to verify that). To allow us to only import FoundationNetworking if required, we use

#if canImport(FoundationNetworking)
import FoundationNetworking
#endif

As you’ve probably surmised URLSession is a shared resource, hence the shared singleton property.

Next we need the URL, which is pretty explanatory. Now the URLSession calls are asynchronous, hence if we just let this code run without the semaphore we’ll exit the application before the response from the web service returns.

The resume method is required to start the task (seems the wrong name to me, but there you go). See dataTask.

Finally we wait on the signal from the semaphore. Within the actual dataTask we’re just going to assume there’s data and no error (ofcourse in a real world application you’ll want to add a guard etc. to check for such things and also check the optionals actual have some value before unwrapping).

In this simple example we’ll simply assuming all worked, unwrap the data and print it to the console. Ofcourse the data will be encoded, so we’re need to create a string from the data and the required encoding as per the String.init.

Now just run the command

swift run

If all went well you’ll see the root level response from the web server code we wrote in the last post.

Getting started with Vapor

Vapor is a web application framework written in Swift.

Installing on Linux

As I’m more likely to be using a Linux server for my web application, that’s what we’ll use for this post. So following the Install on Linux instructione, I went the route of installing the toolbox for the toolbox repo (instructions recreated below)

git clone https://github.com/vapor/toolbox.git
cd toolbox
git checkout <desired version>
make install

This will build and install vapor.

Generating an application

Vapor will generate an application for us using

vapor new hello-vapor -n

(obviously replace hello-vapor with your application name).

As we’re using Linux, we’ll cd into the hello-vapor application folder and then run

swift run

This will run, by default on localhost:8080 which is not great if you want to access remotely, so let’s instead start the application using

swift run Run --hostname 0.0.0.0 --port 8080

Now if you connect to the server’s ip address, port 8080 you should see the default return “It works!” if you use http://localhost:8080/hello you’ll see “Hello, world!” returned.

If you take a look at the source generated by Vapor and check the folder Sources/App/routes.swift you’ll see code like this

import Vapor

func routes(_ app: Application) throws {
    app.get { req in
        return "It works!"
    }

    app.get("hello") { req -> String in
        return "Hello, world!"
    }
}

As you can see this is routing the /hello GET method to return “Hello, world!”.

Using HTTP methods

As you can see from the previous code, app.get denotes the method is a GET method, so let’s simply write an example of each of the HTTP methods, so change your routes.swift file to add the following

app.get("method") { req -> String in
   return "\(req)"
}

app.post("method") { req -> String in
   return "\(req)"
}

app.put("method") { req -> String in
   return "\(req)"
}

app.patch("method") { req -> String in
   return "\(req)"
}

app.delete("method") { req -> String in
   return "\(req)"
}

This doesn’t cover all HTTP methods, but we can use the alternate syntax to the above, which looks like this

app.on(.GET, "method") { req -> String in
   return "\(req)"
}

and simply replace .GET with each of the HTTP methods, such as .CONNECT, .OPTIONS, etc.

Now let’s tests these – if we simply use CURL to execute each method, i.e.

curl -X GET localhost:8080/method
curl -X POST localhost:8080/method
curl -X PUT localhost:8080/method
curl -X PATCH localhost:8080/method
curl -X DELETE localhost:8080/method

Parameters and Query Parameters

We’re also likely to need to handle parameters, so for example /method/aparam

app.get("method", ":param") { req -> String in
   let param = req.parameters.get("param")!        
   return "\(param) --> \(req)"
}

The : prefixing the param token is indicates the parameter is dynamic and hence we need to use req.parameters.get(“param”)! to get the value from the param.

Finally for this post, what about if we want to pass query parameters, for example http://192.168.0.88:8080/method?firstName=Scooby&lastName=Doo

We can declare a struct to handle our expected query parameters like this

struct Person: Content {
    var firstName: String?
    var lastName: String?
}

and now change our GET method to decode the query parameters into this struct, for example

app.get("method") { req -> String in
   let person = try req.query.decode(Person.self)
   return "Firstname: \(person.firstName!), Lastname \(person.lastName!)"
}

There’s a whole lot more functionality, as you’d expect, including streaming, validation etc. take a look at the Vapor Docs.

Publishing my first Rust library to crates.io

As part of my end of 2021 project, I rewrote my F# units of measurement converters to a format which allowed me to code generate a bunch of libraries in different languages, currently including the original F#, C# (both idiomatic to their language), Java, Python, Swift, TypeScript and Rust.

I’ve got the F# and C# ones available on nuget and the TypeScript on npmjs, I wanted to try to get the Rust library onto crates.io.

How do we do this?

  • First off, check if your package name is available on crates.io, if it is then you’ll need to change your name. Rust creates do not support namespaces so you cannot reuse an existing name but prefix with your company or whatever
  • Load up https://crates.io/ and create an account, I think using GitHub to login was the only option, so that’s what I did
  • Ensure you have an email within your profile page and that it’s verified
  • You can go to the API Tokens page and create a new token and a name for the token – you’ll need to copy the API token for the publish step (and keep it for further publishes unless you wish to revoke and regenerate – obviously not too useful in CI. If you set the environment variable CARGO_REGISTRY_TOKEN to the token then cargo will use it from there.
  • Ensure your code is committed (if you’re using source control) or you can always specify the –allow-dirty option if you prefer not to commit changes
  • Ensure you lib.rs has the correct version for your library setup. Semantic versioning is expected, hence you can use -alpha or the likes on your version
  • Now run
    cargo login abcdefghijklmnopqrstuvwxyz
    

    replacing abcdefghijklmnopqrstuvwxyz with your API token

  • Next run
    cargo publish
    

If all the above steps went well you can now search crates.io for your library.

SwiftUI – why is my Mac window not resizable?

As a newbie to SwiftUI, I was surprised to find my simple little sample application would not resize. If you’re used to WPF, WinForms and even other non-Windows user interface libraries, you’ll notice by default the windows are usually resizable. So what’s the deal with SwiftUI

So my code looked like this

var body: some View {
   VStack {
      Text(viewModel.title)
         .padding()
      TextField("Enter", text: $viewModel.title)
   }
   .padding()
   .frame(minWidth: 500, minHeight: 300)
}

Simple enough, display a text label and input text field.

So what’s the problem, why is the Man window not resizable?

Spacer

The Spacer is key here. If we change the code to the following, the it all starts to work as I wanted

var body: some View {
   VStack {
      Text(viewModel.title)
         .padding()
      TextField("Enter", text: $viewModel.title)
      Spacer()
   }
   .padding()
   .frame(minWidth: 500, minHeight: 300)
}

The Spacer expands to fill space.

If you have a Spacer within a VStack the spacer fills space on the vertical and if on an HStack it fills horizontally. But the above code will expand on both the vertical and horizontal. In this case the TextField seems to combine with the Spacer to allow both the axis to expand.

Setting up swift on Ubuntu 20.04

This is an update to Setting up swift on Ubuntu 18.04 – installing Swift on Ubuntu 20.04.

Check out Downloads for the current info. from swift.org.

  • We need to install dependencies, so start with
    apt-get install binutils git gnupg2 libc6-dev libcurl4 libedit2 libgcc-9-dev libpython2.7 libsqlite3-0 libstdc++-9-dev libxml2 libz3-dev pkg-config tzdata uuid-dev zlib1g-dev
    
  • Next we need to download the tar for the version of Swift you’re targeting, mine’s Swift 5.5.2
    wget https://download.swift.org/swift-5.5.2-release/ubuntu2004/swift-5.5.2-RELEASE/swift-5.5.2-RELEASE-ubuntu20.04.tar.gz
    

Next up we should verify this download

  • First download the signature using
    wget https://swift.org/builds/swift-5.5.2-release/ubuntu2004/swift-5.5.2-RELEASE/swift-5.5.2-RELEASE-ubuntu20.04.tar.gz.sig
    
  • Now import the key
    wget -q -O - https://swift.org/keys/all-keys.asc | gpg --import -
    
  • Now run the following
    gpg --keyserver hkp://keyserver.ubuntu.com --refresh-keys Swift
    gpg --verify swift-5.5.2-RELEASE-ubuntu20.04.tar.gz.sig
    

Assuming everything’s verified we now want to extract the download into our preferred location – in my case I am just creating a folder name ~/Swift and extracting the tar to this location, running the following from this location

tar xzf swift-5.5.2-RELEASE-ubuntu20.04.tar.gz

Finally let’s update the path – I’ve added this to the last line of my .bashrc

export PATH=~/Swift/swift-5.5.2-RELEASE-ubuntu20.04/usr/bin:"${PATH}"

Struct, Class and now Record types in C#

I thought it’d be interesting to compare the three C# types, struct, class and record. I’m sure we all know that a struct is a value type and a class a reference type, but what’s a record.

The record “keyword defines a reference type that has built-in functionality for encapsulating data” (see Records (C# reference)).

Before we get into record. let’s review what struct and classes give us using the example of a Person type which has a FirstName property.

struct

struct Person
{
  public string FirstName { get; set; }
}
  • A struct extends System.ValueType and structs are “allocated either on the stack or inline in containing types and deallocated when the stack unwinds or when their containing type gets deallocated. Therefore, allocations and deallocations of value types are in general cheaper than allocations and deallocations of reference types.” See Choosing Between Class and Struct.
  • ToString() will output YouNameSpace.Person by default.
  • Structs cannot be derived from anything else (although they can implement interfaces).
  • Structs should be used instead of classes where instances are small and short-lived or are commonly embedded in other objects.
  • As structs are ValueTypes they are boxed or cast to a reference type or one of the interfaces then implement.
  • As a function of being a ValueType, structs are passed by value

class

class Person
{
  public string FirstName { get; set; }
}
  • A class extends System.Object and classes are reference types and allocated on the heap.
  • ToString() will output YouNameSpace.Person by default.
  • Obviously classes may extend other class but cannot extend a record and vice versa, records cannot extend classes.
  • Reference types are passed by reference.

record

Records can have properties supplied via the constructor and the compiler turns these into readonly properties. The syntax is similar to TypeScript in that we can declare the properties in a terse syntax, such as

record Person(string FirstName);

Whilst records are primarily aimed at being immutable we can still declare them with mutability, i.e.

class Person
{
  public string FirstName { get; set; }
}
  • Records can only inherit for other records, for example
    record Scooby() : PersonRecord("Scooby");
    
  • Records use value comparison (not reference comparison) via IEquatable
  • ToString formats output to show the property values
  • Records support the with keyword which allows us to create a copy of a record and mutate at the point of copying. Obviously as records are generally aimed at being immutable this use of with allows us to copy an existing record with some changes, for example
    var p = somePerson with { FirstName = "Scrappy" };
    

    This is not a great example with our record which has a single property, but if we assume Person also had a LastName property set to “Doo” then we’d essentially have created a new record with the same LastName but now with the new FirstName of “Scrappy”.

    We can also copy whole records by not supplying any values within the { } i.e.

    var p = somePerson with { };
    

Secure storage using Xamarin Essentials

In my post Fingerprint and biometrics authentication in Xamarin Forms I looked at using biometrics (face id/touch id) to authenticate a user.

Using biometrics is pretty useful, but ultimately we’d usually want to use the biometrics along with some way of storing a token, password or whatever. In other words the usual pattern would be something like this

  • Request the user login details and then ask if the user wishes to use biometrics to log into your application (as this post is about using biometrics etc. let’s assume the user does indeed want to use biometrics)
  • Store the token or other details for the successful login within secure storage
  • When the user next try to log into your application, offer an option to use the password to login but by default give an option to login via biometrics
  • Assuming the user selects biometrics, then use the previously show code for biometric authorisations
  • Upon success of the biometrics authorisation, get the token/password etc. from the secure storage and use that to connect to your application/service

So how do we use secure storage within Xamarin forms. The Xamarin Essential nuget package give us SetAsync, for example

await Xamarin.Essentials.SecureStorage.SetAsync(key, token);

and to read back from the storage we use GetAsync, for example

var token = Xamarin.Essentials.SecureStorage.GetAsync(key);

Awk Basics

I’ve been meaning to learn Awk for so many years – this post is just going to cover some basics to getting started for a proper read, check out The GNU Awk User’s Guide.

Note: I’m going to be using Gnu Awk (gawk) as that’s what’s installed by default with my machine, we still type awk to use it. So the commands and programs in this post should still all work on other Awk implementations for the most part.

What is Awk (elevator pitch)

Awk (Aho, Weinberger, Kernighan (Pattern Scanning Language)) is a program and simple programming language for processing data within files. It’s particularly useful for extracting and processing records from files with delimited data.

Example data

Before we get started, this is an example of very simple data file that we’ll use for some of the sample commands – this file is named test1.txt, hence you’ll see this in the sample commands.

One     1
Two     2
Three   3
Four    4
Five    5
Six     6
Seven   7
Eight   8
Nine    9
Ten     10

Running Awk

We run awk from the command line by either supplying all the commands via your terminal or by create files for our commands. The run the command(s) via the terminal just use

awk '{ print }' test1.txt

We can also create files with our awk commands (we’ll use .awk as the file extension) and run them like this (from your terminal)

awk -f sample.awk test1.txt

where our sample.awk file looks like this

{ print }

Awk, like most *nix commands will also take input via the terminal, so if you run the next command you’ll see Awk is waiting for input. Each line you type in the terminal will be processed and output to the screen. Ctrl+D effectively tells Awk you’ve finished your input and at this point the application exits correctly, so if you have any code that runs on completion (we’ll discuss start up and clean up code later), then Awk will correctly process that completion code.

awk '{print}'

Again, standard for *nix commands you can ofcourse pipe from other commands into Awk, so let’s list the directory and let Awk process that data using something like this

ls -l | awk '{ print ">>> " $0 }'

The $0 is discussed in Basic Syntax but to save you checking, it outputs the whole row/record. Hence this code takes ls listing the files in the directory in tabular format, then Awk simply prepends >>> to each row from ls

Basic Syntax

The basic syntax for an awk program is

pattern { action }

So let’s use a grep like pattern match by locating the row in this file that contains the word Nine

awk '/Nine/ { print $0 }' test1.txt

The / indicates a regular expression pattern search. So in this case we’re matching on the word Nine and then the action prints the record/line from the file that contains the expression. $0 basically stands for the variable (if you like) representing the current line (i.e. in this case the matching line). The final argument in this command is ofcourse the data file we’re using awk against. So this example is similar to grep Nine test1.txt.

Actually we can reduce this particular command to

awk '/Nine/' test1.txt

The pattern matching is case sensitive, so we could write the following to ignore case

awk 'tolower($0) ~ /nine/' test1.txt
# or
awk 'BEGIN{IGNORECASE=1} /nine/' test1.txt

In the first example we convert the current record to lower case then use ~ to indicate that we’re trying to match using the pattern matching/regular expression. The second example simple disables case sensitivity.

Awk doesn’t require that we just use pattern matching, we can write Awk language programs, so for example let’s look for any record with a double digit number in the second column (i.e. 10)

awk 'length($2) == 2' test1.txt

As you can see from the above code, we’re using a built-in function length to help us, check out 9.1 Built-in Functions for information on the built-in functions. As you can imagine we have string manipulation functions, numeric functions etc.

Start up and clean up

We can have code run at start of and at the end (or clean up) of an awk program. So for example

awk 'BEGIN {print "start"} { print } END {print "complete"}' test1.txt

In this case we simply display “start” followed by the lines from the file ending with “complete”.

Variables/State

As, I’m sure you’re aware by now, Awk is really a fairly fully fledged programming language. With this in mind you might be wondering if we can store variables in our Awk programs and the answer is yes. Here’s an example (I’ve formatted the code as it’s stored in a file and thus makes it more readable)

BEGIN { 
    count = $2 
}

count += $2 

END { 
    print "Total " count
}

I’m sure it’s obvious from the code, but I’ll go through it anyway – at the start of the application we initialise the count variable to the first row, second column value (in our test1.txt file this is 1) then when Awk processes each subsequent row we simply add to the count and update that until the end where we output the count variable.