Programming and Exciting Things

Равносметката за 2016та

Published on 31.12.2016

Равносметката за тази година може би няма да е толкова лесна колкото очаквах, но за разлика от миналата година, сега се чувствам че съм изпълнил по-голяма част от нещата, които съм планирал за изминалата вече година. Годината беше бурна както в професионален така и в чисто емоционален.
Пътувах доста, надявам се тази година да разширя още повече периметъра си... Италия, идвам :D
Влюбих се, разделих се, преживях доста трудни моменти в личен и емоционален аспект, но имах подкрепата на хората около мен, за което им благодаря от все сърце. Май не съм чак толкова лош човек щом приятелите ми ме търпят все още.
В професионален аспект нещата се стекоха доста благоприятно, имах огромно количество предложения за работа но дори и за мое учудване все още съм в Mansion, даже раста кариерно, май съм уцелил компанията и екипа с който работя. В този контекст искам да благодаря и на всичките ми мениджъри за търпението и вярата в мен, без тяхна помощ шанса да имплементираме Go в prod. среда в такъв бранш би бил немислим.
Какво друго ... а да купих си кола, което от своя страна увеличи пътуванията ми, запознах се с един страхотен човек, който има дейно участие в последните ми разходки по света и у нас и за който се надявам да продължи още дълго време да бъде все така интересна част от живота ми.
Здравословно съм почти добре, ще пропусна тазгодишният ски сезон, но това е дребно неудобство ... просто ще се отдам на СПА :D
Настоящето ... ами то е сложно и продиктувано от прекалена емоционалност, която на моменти пречи на трезвото ми мислене и виждане на очевидни неща, може би се оставям да бъда лъган но все още е рано за да правя заключения.
Може би вече най-важният въпрос е накъде. Имам 2-3 големи идеи които ще се опитам да реализирам, но нека да не издавам все още тайни :) В краткосрочен план искам да затвърдя малко повече знанията си относно някои програмни езици и да дам втори шанс на чистото C++. Въпреки, че към момента съм изключително доволен от избора си да заложа на Go.
Надявам се следващата година да е по-добра, наситена с повече положителни емоции и да съм все така близко до любимите си хора!

Docker redis image

Published on 09.08.2016

From yesterday I'm in process of moving some of my services in new VPS which is based on latest Ubuntu LTS. Some of software that I'm using is "conterized" but not all of them. So moving to new VPS is time to fix that and Redis is first in my list. After quick research I figure out that I preffer to use Phusion base image for Redis also, instead of getting new images :) and because of that I update a little bit original Docker file to:

# Pull base image.
FROM phusion/baseimage:0.9.19

# Install Redis.
RUN \
  cd /tmp && \
  apt-get update && \
  apt-get install wget -y &&\
  apt-get install make -y && apt-get install gcc -y && \
  wget http://download.redis.io/redis-stable.tar.gz && \
  tar xvzf redis-stable.tar.gz && \
  cd redis-stable && \
  make && \
  make install && \
  cp -f src/redis-sentinel /usr/local/bin && \
  mkdir -p /etc/redis && \
  cp -f *.conf /etc/redis && \
  rm -rf /tmp/redis-stable* && \
  sed -i 's/^\(bind .*\)$/# \1/' /etc/redis/redis.conf && \
  sed -i 's/^\(daemonize .*\)$/# \1/' /etc/redis/redis.conf && \
  sed -i 's/^\(dir .*\)$/# \1\ndir \/data/' /etc/redis/redis.conf && \
  sed -i 's/^\(logfile .*\)$/# \1/' /etc/redis/redis.conf

# Define mountable directories.
VOLUME ["/data"]

# Define working directory.
WORKDIR /data

# Define default command.
CMD ["redis-server", "/etc/redis/redis.conf"]
# Expose ports.
EXPOSE 6379
So we can save this in some directory in
Dockerfile
after that we can user
 docker build -t="dockerfile/redis" .
 
Result will something like:
root@sylvester:/tmp/tt# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
dockerfile/redis    latest              fd12d74a4a9d        21 minutes ago      382.2 MB
phusion/baseimage   0.9.19              c39664f3d4e5        4 weeks ago         225.6 MB
That is :) we can quickly use it with something like
docker run -d --name redis -p 6379:6379 dockerfile/redis redis-server --requirepass <password>
Result will be:
root@sylvester:/tmp/tt# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
7efeb6befa28        dockerfile/redis    "redis-server --requi"   11 minutes ago      Up 11 minutes       0.0.0.0:6379->6379/tcp   redis
And woala we have fully functional Redis instance.
Happy codding

Routing specific IP blocks over VPN on MAC OS

Published on 26.07.2016

I have one NAS device at home and I want to access it from office unfortunately default VPN client in MAC OSX doesn't have built in option to specify which traffic to go over current connection, it has only one checkbox which says "Send all traffic over VPN connection" but I don't want to send all traffic over my home router, it's slow and etc.
Probably good option is to use some other VPN clients like "Shimo" but there is other quick and simple solution.
Solution is pretty simple, because I'm using PPTP for VPN which is basically "pppd" program, I can create a script in "/etc/ppp/ip-up" with execution permissions, for example:

cd /etc/ppp
sudo touch ip-up
sudo chmod +x ip-up
And file content can be:
#!/bin/sh

if [ "${5:-}" = "192.168.89.255" ]
then
    /sbin/route add 192.168.88.0/24 $5
fi

IP address
192.168.89.255
is given by VPN server to me and it's same every time.
When the VPN link drops, those routes are automatically removed.
More examples for ip-up script can be found at
http://www.tldp.org/HOWTO/PPP-HOWTO/x1455.html and https://ppp.samba.org/pppd.html

Implement Android Notification Listener using NotificationListenerService

Published on 01.05.2016

NotificationListenerService was introduced from Android team as part of API 18 (Android 4.3), this class allows an application to receive information from notifications when it's created and removed.
To use it we need to implement 2 callback methods. Both of them have paramether named sbn which is object of StatusBarNotification class.
In this example I will show quickly how to listen notification events with just print them to console.logs
Let's start with creating new Java Class named NotificationService.java with following content:

package me.yuks.demo;

import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.util.Log;
import android.support.v4.content.LocalBroadcastManager;


public class NotificationService extends NotificationListenerService {

    Context context;

    @Override

    public void onCreate() {

        super.onCreate();
        context = getApplicationContext();

    }
    @Override

    public void onNotificationPosted(StatusBarNotification sbn) {


        String pack = sbn.getPackageName();

        String text = "";
        String title = "";
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
            Bundle extras = extras = sbn.getNotification().extras;
            text = extras.getCharSequence("android.text").toString();
            title = extras.getString("android.title");
        }

        Log.i("Package",pack);
        Log.i("Title",title);
        Log.i("Text",text);

    }

    @Override
    public void onNotificationRemoved(StatusBarNotification sbn) {
        Log.i("Msg","Notification was removed");
    }
}

Also we need to update our Manifest file to include this newly created service.
<service
    android:name=".NotificationService"
    android:enabled="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
    <intent-filter>
        <action android:name="android.service.notification.NotificationListenerService" />
    </intent-filter>
</service>
So basically that is :) Run and enjoy :) Note: User require to enable notification permission from "Settings > Security > Notification access".

MySQL usage of new JSON field

Published on 25.12.2015

As a part from my new project, I'm using MySQL JSON field which was introduced in version 5.7, functions are described in https://dev.mysql.com/doc/refman/5.7/en/json-functions.html Creating JSON data is pretty simple like:

CREATE TABLE `events` (
	`id` INT(11) NOT NULL AUTO_INCREMENT,
	`site_id` INT(11) NOT NULL,
	`category_id` INT(11) NOT NULL,
	`name` VARCHAR(250) NOT NULL,
	`value` TEXT NULL,
	`added_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
	`custom_data` JSON NULL DEFAULT NULL,
	PRIMARY KEY (`id`),
	INDEX `site_id` (`site_id`, `category_id`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=0;
As you can see Create Table syntax is same, difference is in
 `custom_data` JSON 
. So let's insert some data to it.
INSERT INTO `events` (`id`, `site_id`, `category_id`, `name`, `value`, `added_time`, `custom_data`) VALUES (3, 1, 4, 'fsafsa', '21', '2015-12-21 23:05:56', NULL);
INSERT INTO `events` (`id`, `site_id`, `category_id`, `name`, `value`, `added_time`, `custom_data`) VALUES (4, 1, 4, 'fsafsa', '21', '2015-12-21 23:06:09', NULL);
INSERT INTO `events` (`id`, `site_id`, `category_id`, `name`, `value`, `added_time`, `custom_data`) VALUES (5, 1, 4, 'fsafsa', '2кири', '2015-12-21 23:06:16', NULL);
INSERT INTO `events` (`id`, `site_id`, `category_id`, `name`, `value`, `added_time`, `custom_data`) VALUES (6, 1, 4, 'fsafsa', '2кири', '2015-12-25 10:11:54', '{"dada": {"rpb": "22"}, "test": "dada"}');
INSERT INTO `events` (`id`, `site_id`, `category_id`, `name`, `value`, `added_time`, `custom_data`) VALUES (7, 1, 1, 'test', '1', '2015-12-25 17:26:04', NULL);
INSERT INTO `events` (`id`, `site_id`, `category_id`, `name`, `value`, `added_time`, `custom_data`) VALUES (8, 1, 1, '1da', '2', '2015-12-25 17:26:10', '{"test": "dada"}');

And lets assume that we want to filter data in JSON field.
SELECT  id,custom_data FROM `events` WHERE JSON_UNQUOTE(custom_data->"$.test") = "dada"
Result is:
+----+-----------------------------------------+
| id | custom_data                             |
+----+-----------------------------------------+
|  6 | {"dada": {"rpb": "22"}, "test": "dada"} |
|  8 | {"test": "dada"}                        |
+----+-----------------------------------------+
2 rows in set (0.00 sec)
Or if we want to check existence of sub element:
SELECT id,custom_data  FROM `events` WHERE  JSON_CONTAINS_PATH(custom_data,"all","$.dada.rpb");
Result is:
+----+-----------------------------------------+
| id | custom_data                             |
+----+-----------------------------------------+
|  6 | {"dada": {"rpb": "22"}, "test": "dada"} |
+----+-----------------------------------------+
1 row in set (0.00 sec)
And one more example for extracting value from JSON:
SELECT 
	id,
	JSON_UNQUOTE(JSON_EXTRACT(custom_data,'$.test')) AS value
FROM `events`
WHERE JSON_EXTRACT(custom_data,'$.test') IS NOT NULL
+----+-------+
| id | value |
+----+-------+
|  6 | dada  |
|  8 | dada  |
+----+-------+
2 rows in set (0.00 sec)

It's look pretty easy, right ? :)