Рубрика: Программизмы

Asterisk, Lua и MySQL. Добавляем номер в черный список

Табличка немного отличается от предыдущего поста, поле number уникальное.

Пишем макрос:

extensions['macro-ban'] = {
        s = function()
                cid = channel.CALLERID("num"):get()
                query = "INSERT INTO blacklist (number, expires) VALUES ('" .. cid .. "', date_add(NOW(), INTERVAL 1 DAY)) on duplicate key update expires = date_add(NOW() INTERVAL 1 DAY);"
                local con = assert (env:connect(DB_NAME,DB_USER,DB_PASSWORD))
                assert (con:execute(query))
                con:close()
        end
};

Добалвяем макрос в features.conf:

[applicationmap]
ban => *5,peer/callee,macro(ban)

и не забываем включить в __DYNAMIC_FEATURES в диалплане:

extensions = {
    ["incoming"] = {
        ["DID"] = function()
            channel.__DYNAMIC_FEATURES = "ban"
            app.dial("SIP/100")
        end;
    }
}

Теперь ответивший нажатием *5 может добавить номер звонящего в черный список.

Asterisk, LUA и MySQL. Черный Список.

С помощью LUA делается элементарно:

В MySQL делаем табличку blacklist:

CREATE TABLE blacklist (
  NUMBER VARCHAR(20) NOT NULL,
  expires datetime DEFAULT NULL
)

Подключаем к LUA библиотеку luaSQL и luasql.mysql для работы с базой данных

 
-- расскажем, где искать
package.cpath = package.cpath .. ";/usr/lib/i386-linux-gnu/lua/5.1/?.so" 
-- и подключем
local luasql = require "luasql.mysql"
local mysql = assert (luasql.mysql())
 
-- данные для подключения к базе MySQL
local DB_HOST = "localhost"
local DB_NAME = "db_name"
local DB_USER = "db_user"
local DB_PASSWORD = "db_passwod"
 
-- и пишем функцию проверки: 
function is_banned(cid_number)
        local con = assert (env:connect(DB_NAME,DB_USER,DB_PASSWORD))
        local cur = assert (con:execute("SELECT * FROM blacklist where '".. cid_number.."' like number and (expires>now() or expires is NULL);"))
        c = cur:numrows()
        cur:close()
        con:close()
        return c>0
end
 
 
-- а дальше и начинаем использовать:
 
extensions = {
    ["incoming"] = {
        ["DID"] = function() 
            if is_banned(channel.CALLERID["number"]:get()) then
                -- Номер в черном списке, что-то с ним делаем
                app.answer()
                app.wait(1)
                app.hangup()
            end;
        end;
    }
}

Конечно, для полноценного использования нужно добавить индексы в базу и по-хорошему еще разрулить ситуацию, когда база данных недоступна.
А чуть позже мы добавим бан номера по кнопке оператора.

Asterisk и Lua. Очень быстрый старт

Астериск из коробки может исползовать язык программирования LUA для написания диалплана. И это прекрасно! В диалплане можно подключить любую установленную lua-библиотеку и получить доступ к базе данных (SQLite, MySQL, PostgreSQL), работать с сетью, читать-записывать файлики. Причем, делается это все довольно просто.
Зная любой язык программирования и вооружившись справочником по синтаксису LUA, а так же прочитав пару абзацев ниже можно без проблем начать использовать всю мощь этой связки.
Читать далее

AVR CMake

Clion & AVRВот уже несколько лет пользуюсь CMake-ом, чтобы собирать проекты под AVR. Сподвиг на этом конечно же вышедший осенью 2014 Jetbrains CLion, который как оказалось идеально подходит для написания кода под Atmel AVR. Короче, рекомендую.
Возможно, для корректной работы нужно будет установить переменную среды AVR_FIND_ROOT_PATH — на папку с avr (содержащую lib и include), а так же папка с avr-gcc, avr-g++, avr-objcopy, avr-size должны находиться в PATH. Ну или доработать напильником generic-gcc-avr.cmake

В общем, шаблон тут: https://github.com/bevice/avr_cmake_template
Читать далее

UART размер экрана

Для общения через UART с железками (avr, stm32 и прочими) в основном использую GNU screen:

$ screen /dev/tty.ubserial 9600

А вот что-то дернуло, раскрасить вывод микроконтроллера и раскрасил (не мудрено, печатаем что-то вроде \033[31m и вперед, ну только цвета меняем). А потом поехало: захотелось печатать в разных местах экрана (\033[y;xH), а вот как напечатать в центре? Надо же знать размер экрана, а он у меня (да и у всех) каждый раз разный.
Долго возился, выяснил, что screen отдавать размер окна (\033[18t) не умеет. Зато DCS передает напрямую терминалу из которого запущен: вот и нашелся грязный хак: оборачиваем запрос размера в ESC-P последовательность, и вот уже знаем размер экрана.
Печатаем хитрую строку:

\033P\033[18t033\

и получаем ответ:

\[8;31;163t

31 строка, 163 колонки, а 8 — это номер CSI-репорта. Он всегда такой.

вот тут большой список похоже что вообще всех ESC-последовательностей которые терминалы поддерживают: ttssh2.osdn.jp

P.S.
Ну а бонусом — таким же способом можно поставить заголовок окна который screen ставить умеет только через жопу.

\033P\033]0;New Window Title\a\033\\

responseText ошибки при AJAX-запросе

За формирование страницы ошибки отвечает функция technical_500_response из django.views.debug,
программисты джанги пошли странным путем, жестко задав (без возможности настройки): если запрос AJAX — ответ будет текстом, в остальных случаях HTML.
Все бы ничего, но raise Http404(), например, плевать на этот механизм хотела, и все равно выбрасывает HTML, если выводить ошибку в консоль — сущий ад.
Изменить поведение можно например так:
Добавить Middleware которая, в случае ошибки уберет из request соответствующий заголовок,
дальше джанга отработает по своему алгоритму и вернет красивый HTML.
Криво конечно, т.к. пропадает возможность узнать был Ajax или не было, но не нужно патчить Django

1
2
3
4
class DisableAjaxException(object):
    @staticmethod
    def process_exception(req, exception):
        req.META['HTTP_X_REQUESTED_WITH'] = None

Ну и остается напомнить, порядок Middleware в settings.py важен

MySQL и foreign key constraint fails

Cannot add or update a child row: a foreign key constraint fails
Такое случается, если включена проверка InnoDB foreign key, но ссылается ключ на таблицу не InnoDB (например MyISAM)
лечится:

  • конвертированием всех таблиц в InnoDB
  • конвертирование всех таблиц в MyISAM
  • или отключением проверки:
DATABASES = {
'default': {
    ...         
    'OPTIONS': {
         "init_command": "SET foreign_key_checks = 0;",
    },
 }
}

Статейка про InnoDB

Плеер в iOS

Music player

 
 
//Тут лежит MPNowPlayingInfoCenter и прочие MP*    
#import <mediaplayer /MediaPlayer.h>
 
 
 
 NSString * path = [[NSBundle mainBundle]pathForResource:@"some_track" ofType:@"mp3"];
 NSURL *url = [NSURL fileURLWithPath:path];
//Создаем плеер
 
AVAudioPlayer * player;
player  = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
//Задаем громкость
player.volume = 1.0f;
//Загружаем файл в буффер 
[player prepareToPlay];	
//Разрешаем играть в фоне
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback  error:nil];
 
//Загружаем обложку
UIImage * artwork = [UIImage imageNamed:@"Artwork.jpg"];
//Создаем словарь с параметрами now playing
NSDictionary * info = @{MPMediaItemPropertyAlbumTitle: @"Astronimia",
                        MPMediaItemPropertyArtist: @"TONY IGY",
                        MPMediaItemPropertyArtwork: [[MPMediaItemArtwork alloc] initWithImage:artwork]
                        };
//Отправляем созданное в куда следует
[MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo = info;
 
 
// Управление, со шторки, наушников, экрана блокировки
 
//Начинаем принимать события
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
//Заканчиваем принимать события
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];
 
//Обработчик событий
-(void) remoteControlReceivedWithEvent:(UIEvent *)event {
    if(event.type == UIEventTypeRemoteControl){
        switch (event.subtype) {
            case UIEventSubtypeRemoteControlTogglePlayPause:
            case UIEventSubtypeRemoteControlPlay:
            case UIEventSubtypeRemoteControlPause:
                [self togglePlayPause];
                break;
            default:
                break;
        }
    }
}
</mediaplayer>