protocol buffer e libra

Protocol buffers e gRPC

Protocol Buffesr o protobuff per gli amici è un protocollo versatile per serializzare dati strutturati e definire servizi RPC.

Perchè protocol buffers è versatile?

  • E’ indipendente dai linguaggi di programmazione.
  • E’ indipendente dalle piattaforme.
  • Può essere utilizzato nei protocolli di comunicazione, come nei data storage.
  • E’ molto ben documentato.
message Person {
  string name = 1;
  int32 id = 2;
  optional string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    string number = 1;
    optional PhoneType type = 2 [default = HOME];
  }

  repeated PhoneNumber phone = 4;
}

Come potete vedere la sintassi è molto semplice. Andiamo per gradi.
Con “message Person { ..}” definiamo un tipo di messaggio chiamato Person.
string name = 1 è uno dei quattro field appartenenti al messaggio.
Possiamo usare le keyword optional se vogliamo renderlo opzionale, oppure repeated se vogliamo ripeterlo da 0 a molte volte.
String indica che il tipo di field è una stringa, name è il nome del field, mentre “= 1” non sta ad indicare che il field ha valore 1, ma in protobuff ogni definizione dei field deve avere un numero univoco, identificativo.
la documentazione ufficiale dice:

As you can see, each field in the message definition has a unique number. These field numbers are used to identify your fields in the message binary format, and should not be changed once your message type is in use. 

Per quanto riguarda tutti i tipi di variabile, con la relativa conversione nel linguaggio scelto, la Documentazione ufficiale ci viene incontro con una tabella ben dettagliata.

I messaggi sono niente senza RPC (Remote Procedure Call)

Per utilizzare i messaggi definiti in precedenza attraverso un sistema RPC è necessario definire l’interfaccia di un servizio in un .proto file.

service SearchService {
  rpc Search (SearchRequest) returns (SearchResponse);
}

Protocol Buffer compilerà il file .proto e genererà il codice dell’interfaccia e degli stub (nel linguaggio da te scelto. Un esempio più completo, preso da qua:

syntax = "proto3";

service FooService {
  rpc GetFoo (GetFooRequest) returns (GetFooResponse);
}
message GetFooRequest {
  string id = 1;
}
message GetFooResponse {
  string fooName = 1;
  int64 fooValue = 2;
}

gRPC ..wut?

gRPC

gRPC può usare i Protocol Buffer sia per le definizioni delle interfacce ( i service), sia come formato di interscambio di messaggi (i message).

Installazione

Prima di tutto è necessario creare un virtualenv di python 3.6, per chi ha mkvirtuaenv:

$ mkvirtualenv grpc_test --python=/usr/bin/python3.6

altrimenti:

$ python -m pip install virtualenv
$ virtualenv grpc_test -p=python3.6
$ source venv/bin/activate
$ python -m pip install --upgrade pip

Successivamente attivate il virtualenv e poi:

$ pip install grpcio
$ pip install grpcio-tools

Salviamo il file di prima con il nome example.proto e lanciamo il seguente comando:

$ python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. example.proto

l’output saranno due file python. Il primo example_pb2.py

# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler.  DO NOT EDIT!
# source: example.proto

import sys
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)

_sym_db = _symbol_database.Default()




DESCRIPTOR = _descriptor.FileDescriptor(
  name='example.proto',
  package='',
  syntax='proto3',
  serialized_options=None,
  serialized_pb=_b('\n\rexample.proto\"\x1b\n\rGetFooRequest\x12\n\n\x02id\x18\x01 \x01(\t\"3\n\x0eGetFooResponse\x12\x0f\n\x07\x66ooName\x18\x01 \x01(\t\x12\x10\n\x08\x66ooValue\x18\x02 \x01(\x03\x32\x37\n\nFooService\x12)\n\x06GetFoo\x12\x0e.GetFooRequest\x1a\x0f.GetFooResponseb\x06proto3')
)




_GETFOOREQUEST = _descriptor.Descriptor(
  name='GetFooRequest',
  full_name='GetFooRequest',
  filename=None,
  file=DESCRIPTOR,
  containing_type=None,
  fields=[
    _descriptor.FieldDescriptor(
      name='id', full_name='GetFooRequest.id', index=0,
      number=1, type=9, cpp_type=9, label=1,
      has_default_value=False, default_value=_b("").decode('utf-8'),
      message_type=None, enum_type=None, containing_type=None,
      is_extension=False, extension_scope=None,
      serialized_options=None, file=DESCRIPTOR),
  ],
  extensions=[
  ],
  nested_types=[],
  enum_types=[
  ],
  serialized_options=None,
  is_extendable=False,
  syntax='proto3',
  extension_ranges=[],
  oneofs=[
  ],
  serialized_start=17,
  serialized_end=44,
)


_GETFOORESPONSE = _descriptor.Descriptor(
  name='GetFooResponse',
  full_name='GetFooResponse',
  filename=None,
  file=DESCRIPTOR,
  containing_type=None,
  fields=[
    _descriptor.FieldDescriptor(
      name='fooName', full_name='GetFooResponse.fooName', index=0,
      number=1, type=9, cpp_type=9, label=1,
      has_default_value=False, default_value=_b("").decode('utf-8'),
      message_type=None, enum_type=None, containing_type=None,
      is_extension=False, extension_scope=None,
      serialized_options=None, file=DESCRIPTOR),
    _descriptor.FieldDescriptor(
      name='fooValue', full_name='GetFooResponse.fooValue', index=1,
      number=2, type=3, cpp_type=2, label=1,
      has_default_value=False, default_value=0,
      message_type=None, enum_type=None, containing_type=None,
      is_extension=False, extension_scope=None,
      serialized_options=None, file=DESCRIPTOR),
  ],
  extensions=[
  ],
  nested_types=[],
  enum_types=[
  ],
  serialized_options=None,
  is_extendable=False,
  syntax='proto3',
  extension_ranges=[],
  oneofs=[
  ],
  serialized_start=46,
  serialized_end=97,
)

DESCRIPTOR.message_types_by_name['GetFooRequest'] = _GETFOOREQUEST
DESCRIPTOR.message_types_by_name['GetFooResponse'] = _GETFOORESPONSE
_sym_db.RegisterFileDescriptor(DESCRIPTOR)

GetFooRequest = _reflection.GeneratedProtocolMessageType('GetFooRequest', (_message.Message,), dict(
  DESCRIPTOR = _GETFOOREQUEST,
  __module__ = 'example_pb2'
  # @@protoc_insertion_point(class_scope:GetFooRequest)
  ))
_sym_db.RegisterMessage(GetFooRequest)

GetFooResponse = _reflection.GeneratedProtocolMessageType('GetFooResponse', (_message.Message,), dict(
  DESCRIPTOR = _GETFOORESPONSE,
  __module__ = 'example_pb2'
  # @@protoc_insertion_point(class_scope:GetFooResponse)
  ))
_sym_db.RegisterMessage(GetFooResponse)



_FOOSERVICE = _descriptor.ServiceDescriptor(
  name='FooService',
  full_name='FooService',
  file=DESCRIPTOR,
  index=0,
  serialized_options=None,
  serialized_start=99,
  serialized_end=154,
  methods=[
  _descriptor.MethodDescriptor(
    name='GetFoo',
    full_name='FooService.GetFoo',
    index=0,
    containing_service=None,
    input_type=_GETFOOREQUEST,
    output_type=_GETFOORESPONSE,
    serialized_options=None,
  ),
])
_sym_db.RegisterServiceDescriptor(_FOOSERVICE)

DESCRIPTOR.services_by_name['FooService'] = _FOOSERVICE

# @@protoc_insertion_point(module_scope)

il secondo example_pb2_grpc.py

# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
import grpc

import example_pb2 as example__pb2


class FooServiceStub(object):
  # missing associated documentation comment in .proto file
  pass

  def __init__(self, channel):
    """Constructor.

    Args:
      channel: A grpc.Channel.
    """
    self.GetFoo = channel.unary_unary(
        '/FooService/GetFoo',
        request_serializer=example__pb2.GetFooRequest.SerializeToString,
        response_deserializer=example__pb2.GetFooResponse.FromString,
        )


class FooServiceServicer(object):
  # missing associated documentation comment in .proto file
  pass

  def GetFoo(self, request, context):
    # missing associated documentation comment in .proto file
    pass
    context.set_code(grpc.StatusCode.UNIMPLEMENTED)
    context.set_details('Method not implemented!')
    raise NotImplementedError('Method not implemented!')


def add_FooServiceServicer_to_server(servicer, server):
  rpc_method_handlers = {
      'GetFoo': grpc.unary_unary_rpc_method_handler(
          servicer.GetFoo,
          request_deserializer=example__pb2.GetFooRequest.FromString,
          response_serializer=example__pb2.GetFooResponse.SerializeToString,
      ),
  }
  generic_handler = grpc.method_handlers_generic_handler(
      'FooService', rpc_method_handlers)
  server.add_generic_rpc_handlers((generic_handler,))

Adesso implementiamo il server my_server.py:

from concurrent import futures
import time
import logging

import grpc

import example_pb2
import example_pb2_grpc

_ONE_DAY_IN_SECONDS = 60 * 60 * 24


class FooService(example_pb2_grpc.FooServiceServicer):

    def GetFoo(self, request, context):
        return example_pb2.GetFooResponse(fooName='Hello, %s!' % request.id)


def serve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    example_pb2_grpc.add_FooServiceServicer_to_server(FooService(), server)
    server.add_insecure_port('[::]:50051')
    server.start()
    try:
        while True:
            time.sleep(_ONE_DAY_IN_SECONDS)
    except KeyboardInterrupt:
        server.stop(0)


if __name__ == '__main__':
    logging.basicConfig()
    serve()

Da notare il fatto che
la definizione nel nostro Proto file è passata da;

service FooService {
  rpc GetFoo (GetFooRequest) returns (GetFooResponse);
}

a così in Python:

class FooService(example_pb2_grpc.FooServiceServicer):

    def GetFoo(self, request, context):
        return example_pb2.GetFooResponse(fooName='Hello, %s!' % request.id)

il parametro request in ingresso alla GetFoo non è altro che un’istanza della classe GetFooRequest. Infatti accediamo al parametro id.

Il client sarà my_client.py:

 
from __future__ import print_function
import logging

import grpc

import example_pb2
import example_pb2_grpc


def run():
    with grpc.insecure_channel('localhost:50051') as channel:
        stub = example_pb2_grpc.FooServiceStub(channel)
        response = stub.GetFoo(example_pb2.GetFooRequest(id='ciao ale'))
    print("Greeter client received: " + response.fooName)


if __name__ == '__main__':
    logging.basicConfig()
    run()

Per far funzionare il tutto, basterà lanciare prima my_server.py e successivamente my_client.py e l’output che ottenendo questo output:

$ Greeter client received: Hello, ciao ale!

Perchè questa guida? Perchè Libra ha tutti i servizi definiti in .proto files ed un codice in Rust.

FA instagram

Come creare un instagram bot per automatizzare like e follow.

Se io fossi Aranzulla inizierei scrivendo questo post dicendovi cosa è Instagram, ma io non sono Aranzulla (sempre sia lodato) e quindi assumo il fatto che voi sappiate cosa è Instagram.
Un Bot invece è un software che automatizza dei compiti che solitamente dovrebbero essere svolti a mano. In definitiva un instagram bot, è un software che automatizza delle azioni su Instagram. Like, commenti, follow e defollow.

E’ legale usare dei Bot su instagram?

No.

Ma ci sono dei servizi a pagamento che forniscono dei bot!

Nel caso in cui non siano ufficialmente autorizzati da Instagram ad usare le loro API, li puoi usare a tuo rischio e pericolo. Il bot che ti illustrerò successivamente è gratuito, ma viole le policy di Instagram.

Maggiori informazioni qua

Come funziona questo Instagram bot in python?

instabot.py è un progetto Open Source che potete trovare su Github e funziona fingendosi un browser web e usando le API web di Instagram. Infatti spulciando nel suo codice si trova questa sezione qua:

    "list_of_ua": [
        "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FSL 7.0.6.01001)",
        "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FSL 7.0.7.01001)",
        "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FSL 7.0.5.01003)",
        "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0",
        "Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9.2.8) Gecko/20100723 Ubuntu/10.04 (lucid) Firefox/3.6.8",
        "Mozilla/5.0 (Windows NT 5.1; rv:13.0) Gecko/20100101 Firefox/13.0.1",
        "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:11.0) Gecko/20100101 Firefox/11.0",
        "Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9.2.8) Gecko/20100723 Ubuntu/10.04 (lucid) Firefox/3.6.8",
        "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705)",
        "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)",
        "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)",
        "Opera/9.80 (Windows NT 5.1; U; en) Presto/2.10.289 Version/12.01",
        "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727)",
        "Mozilla/5.0 (Windows NT 5.1; rv:5.0.1) Gecko/20100101 Firefox/5.0.1",
        "Mozilla/5.0 (Windows NT 6.1; rv:5.0) Gecko/20100101 Firefox/5.02",
        "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 Safari/535.1",
        "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows NT 5.0) Opera 7.02 Bork-edition [en]",

che elenca i possibili Usera Agent con cui instabot si presenta a Instagram.

Primo step, installare il virtualenvwrapper, per gestire al meglio i virtualenv.

sudo pip install virtualenvwrapper

Chiudiamo il terminale e riapriamolo. Creiamo una cartella:

mkdir InstagramBot

e creaiamo il virtualenv:

mkvirtualenv instabot --python=/usr/bin/python3.6

mkvirtualenv è il comando per creare il virtualenv, instabot è il nome del’ambiente e con “–python=/usr/bin/python3.6” specifichiamo la versione di python da usare

Un rapido controllo per vedere se il virtuaenv è attivo, è quello di notare la scritta a sinistra del nome nel terminale:

(instabot) fabio@apptec-dev ~/instabot

Se così non fosse, basta lanciare il comando:

workon instabot

Attivato il virtulenv non rimane che installare i pacchetti:

pip install instabot-py
pip install pyyaml

pyyaml bisogna installarlo a mano, perché per qualche arcano motivo non è incluso fra le dipendenze di instabot.

Per avviare instabot si deve lanciare il comando

instabot-py

e vi verranno poste delle domande che vanno dal nome utente, a come commentare, come seguire e così via.
Nel caso in cui aveste risposto in maniera errata, avete due possibilità:
La prima è quella di premere CTRL+C e uscire dall’applicazione, cancellare il file .sessions, il file instabot.config.ini e il file sqlite.db
L’altra possibilità è quella di arrivare fino in fondo alla procedura di configurazione e poi aprire il file instabot.config.ini ed editare i campi che contenevano gli errori.

Anche se la procedura si è conclusa a dovere, vi consiglio di aprire il file instabot.config.ini e di controllare che tutto sia configurato a dovere.
(Fidarsi è bene, non fidarsi è meglio)

nano instabot.config.ini

Ricordatevi di non esagerare con i like, con i follow e defollow, ma sopratutto non condividete il file instabot.config.ini con nessuno, perché sopra c’è salvata la vostra password in chiaro.

Per ri-avviare l’applicazione basterà lanciare il comando:

instabot-py

(assicuratevi sempre di avere il virtuaenv attivo)