Rus9n by Boris Kimel

Blog (about everything)

29.04.2023 Converting Microsoft glossaries

As per Microsoft's announcement, their terminology lookup site is to be taken down soon. They provide downloadable files in TBX format, which are actually Martif xml. I wrote a dumb command line utility to convert these TBX to tab-delimited text files. No warranties.

MacOS binary: download (Apple CPU)

Windows binary: download (Not tested)

How it works: put the binary into the folder with the downloaded MicrosoftTermCollection.tbx file and run the binary from the command line. It will produce a tab-delimited out.txt. MacOS users might need to use

xattr -d com.apple.quarantine msgloss
to be able to run a binary from an unknown source.

31.01.2022 Displaying temperatures on camera

Occasionally found out the Hikvision IP camera is able to display a second line of text. And this line can be updated by sending an HTTP request. Many people out there use it to display additional data, e. g. temperature. Modified the logger service to update the camera with the relevant values (asynchronously):

func UpdateCamera(t1, t2, t3 float64) {
  xmlBefore := `<?xml version="1.0" encoding="UTF-8"?><TextOverlay version="1.0" xmlns="http://www.hikvision.com/ver20/XMLSchema"><id>1</id><enabled>true</enabled><positionX>32</positionX><positionY>512</positionY><displayText>`
  xmlAfter := `</displayText></TextOverlay>`
  xmlComplete := fmt.Sprintf("%sOut: %.2f In: %.2f Bath: %.2f%s", xmlBefore, t1, t2, t3, xmlAfter)
  url := "http://192.168.0.190/ISAPI/System/Video/inputs/channels/1/overlays/text"
  req, err := http.NewRequest(http.MethodPut, url, strings.NewReader(xmlComplete))
  if err != nil {
    panic(err)
  }
  req.SetBasicAuth("user", "password")
  req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
  resp, err := http.DefaultClient.Do(req)
  if err != nil {
    panic(err)
  }
  defer resp.Body.Close()
}
                

Looks like this:

24.01.2022 Moving to Arch Linux

Succesfully moved the production server (this one) to a minimal installation of Arch Linux. It might seem a bit tricky compared to the modern graphical installers, still nice to handle everything oneself. All the graphical UI has gone, since it's more time configuring and almost no time in use. Verified Visual Studio Code working via SSH, and restored the good old emacs to handle Go. And yes, golang gets updated the next daty after release by the system package manager, no need to download and untar.

14.10.2020 First Blog Post and Some Visual Studio Code

This is just for starters. No blog engine so far, just a generic entry. My site resides in a single VS Code workspace and includes some source in Go and all the required files – templates, images, styles etc. There are two basic tasks so far beyond development and content creation: running the server locally and deloying everything onto the production server. I've seen there are some extensions to help out there, but for now the VS code tasks do the job quite smoothly. In the meanwhile there is some development about the tasks at the link above, but my versions look more like legacy ones.

Running the server locally

This is pretty simple. All we need is to build the binary and start it. All the rest is already where it needs to be.

{
    "label": "Run Locally",
    "type": "shell",
    "command": "go build -o bin/www && ./bin/www",
    "problemMatcher": [
        "$go"
    ]
}

The command here is pretty straightforward. The go build -o bin/www naturally builds the server binary, placing the output into the bin/www, while the problemMatcher ensures proper parsing of the possible compiler error messages. The && operator checks for the build success and starts the binary via ./bin/www. That's all.

Deploying onto the production machine

This is not so easy, but actually just needs more steps. Copying over the (changed) files, building the binary at the remote computer, and restarting the daemon. Not too much really. Here is the task:

{
    "label": "Deploy",
    "type": "shell",
    "command": "rsync -avzr --exclude 'bin/*' ${workspaceFolder} 10.9.8.1:~/Sites/ && ssh -t 10.9.8.1 'chmod +x ~/Sites/www/deploy.sh && ~/Sites/www/deploy.sh'",
    "problemMatcher": []
}

The connection to the remote machine is a VPN, so the IP is local. SSH authentication uses keys, so no password is needed. First of all, the rsync command incrementally copies all the files onto the remote machine. The options are as follows:

  • -a enables archive mode
  • -v prints verbose info
  • -z compresses the data during the transfer
  • -r enables recursive mode (not needed, already included by the -a)

Further on, the --exclude 'bin/*' prevents from copying the local binary, which is big and of no use on a different platform. The whole local workspace folder identified by the VS Code's macro ${workspaceFolder} is synced into the Sites directory within my home on the remote system. Upon success (the && operator), ssh session to the remote machine is started. The -t flag forces a terminal allocation at the remote to facilitate running further commands. All the remote work is done by the deploy.sh shell script, so here wee just make it executable using chmod +x and run it. Here is the script:

    #!/bin/bash
    source ~/.profile
    echo "Profile read."
    cd ~/Sites/www
    echo "Directory changed."
    go build -o bin/www
    echo "Binary built."
    cp www.service ~/.config/systemd/user/www.service
    echo "Unit copied."
    systemctl --user daemon-reload
    echo "Daemon reloaded."
    systemctl --user restart www.service
    echo "Service restarted."

And again, the workflow is fairly simple. For the sake of Go, we read the ~/.profile settings, ensuring proper environment is here. After navigating to the proper working folder, we build the binary using the same command as for the local build. The www.service unit file is copied into the folder where the systemd will be able to find it. And the last two commands reload the systemd daemon, picking up the copied unit (not needed normally, since the unit is rarely changed), and restart the daemon as specified by the unit file. Please note there is no error checking here, just the command sequence – which will be successful most of the time.

The unit file itself and systemd usage are pretty basic here. The only noteworthy issue is that the daemon is running as a regular user to avoid using root access, but this needs some extra preparation. Let's look at this and the unit itself in the next post.

Please stay tuned!