CoBang, phần mềm quét mã QR cho Linux

Năm 2020 quả là một năm với nhiều biến động lớn, quy mô rung chuyển toàn cầu, tiêu điểm là dịch cúm CoVid-19 khiến nhiều cường quốc mất mặt và một nước "ít quan trọng" như Việt Nam trở thành điểm sáng. Hòa chung xu thế đó mình cũng tung ra một phần mềm "Made in Viet Nam" nhưng hướng đến người dùng quốc tế. Chém thế thôi chứ nó thật ra xuất phát từ nhu cầu cá nhân.

CoBang

CoBang là phần mềm quét mã QR dành cho desktop Linux. Mã QR đang ngày càng phổ biến, nó là phương tiện để trao đổi thông tin khó viết và khó nhớ. Một trong những hoàn cảnh mình bị buộc phải đụng đến mã QR là khi mình cần kết nối vào một mạng wifi nhưng không biết password. Thông tin wifi đó thì có lưu trong điện thoại nhưng điện thoại không cho xem password (một quan điểm kì cục của những người thiết kế HĐH điện thoại ban đầu). May thay hồi đó mình dùng điện thoại Xiaomi và nó nó chức năng chia sẻ thông tin wifi qua mã QR. Trong khi những phần mềm quét mã QR có ra rả trên Android thì trên Linux lại rất hiếm. Lí do của sự hiếm này là khi nói đến "quét mã QR", người ta chỉ hình dung đến việc cầm điện thoại lên soi thôi. Hồi đó trên laptop mình dùng QtQR nhưng khá cùi và có bug. Điều đó làm nảy sinh nhu cầu bức thiết là phải tạo một phần mềm mới. Dù nhu cầu là có nhưng vì có nhiều công việc gấp hơn nên mình đành trì hoãn đến năm nay mới bắt tay vào làm, nhân dịp muốn tìm một luồng gió mới thay cho công việc làm web hàng ngày.

Do cũng khá am hiểu những lớp công nghệ bên dưới desktop Linux nên mình dễ dàng hình dung được việc cần dùng những thư viện, công nghệ gì bên dưới và liên kết chúng ra sao. Thành tố quan trọng nhất là GStreamer, một thư viện/framework xuất sắc của thế giới Linux. Nó giúp hiện thực hóa ý tưởng của mình về cách luồng media vận hành ra sao: Sau khi lấy nguồn video liên tục từ webcam thì dòng video sẽ được chia làm 2 nhánh, một nhánh cho hiển thị lên cửa sổ giao diện, nhánh kia thì cho tách ra từng frame, lấy ảnh, và cho vào thư viện ZBar để soi tìm mã QR. Về giao diện đồ họa thì mình đi ngược với hot trend "cross-platform" để gắn bó với GTK, một thư viện native trên Linux.

Mục tiêu lớn mà mình chú tâm khi viết mới phần mềm này là sự hỗ trợ Wayland, một giao thức mới cho display server trên Linux. Vì yếu tố này mà mình hơi sa lầy một thời gian cho việc tìm kiếm tài liệu GStreamer dành cho môi trường Wayland. Mãi một hồi liên lạc được với tác giả của GStreamer mới được chỉ một lời giải đúng, đơn giản nhưng mỗi tội không được kể ra trong tài liệu.

Sẽ có người thắc mắc, tại sao mình không sửa code của QtQR mà phải tạo phần mềm mới, nó open source mà? Đây là những lý do:

  • Ngoài QtQR, mình có thử tìm phần mềm khác thay thế, và chỉ thấy 1-2 phần mềm khác, dựa trên Electron, giới thiệu trên GitHub. Tất cả các phần mềm này chỉ chạy trên X Window System, không hỗ trợ Wayland. Code của QtQR thì quá cũ nên việc không hỗ trợ Wayland là điều không có gì ngạc nhiên. Còn Electron thì..., nó là framework cross-platform nên sẽ có điểm yếu về việc tích hợp sâu với một nền tảng, cụ thể là với Linux, nên việc nó không hỗ trợ Wayland cũng là một điểm yếu tất yếu, cái giá phải trả cho việc "cross-platform".
  • Không những code của QtQR quá cũ mà ngay cả cấu trúc của nó đã có vấn đề. Thay vì tự lấy nguồn video từ webcam thì nó dựa vào một tính năng của ZBar, chạy một process riêng để mở video webcam. Hậu quả là tự dưng nảy ra thêm cửa sổ dành cho webcam, chưa kể process này sẽ phụ thuộc vào công nghệ cũ của Linux (không hỗ trợ Wayland), vì ZBar không chuyên về multimedia để giải quyết những vấn đề xung quanh.

Với việc code quá cũ và kiến trúc phần mềm bất cập thì việc sửa lại QtQR còn tốn công và chán ngắt hơn việc viết phần mềm mới.

Ban đầu mình chỉ định phát hành nó trên PPA cho người dùng Ubuntu phụ test, nhưng khi công bố dự án trên Reddit, khá nhiều người hỏi thăm và đề nghị mình phát hành trên FlatHub để họ có thể tải về dùng thử, do họ không xài Ubuntu để mà cài được gói trên PPA. Sau bao nhiêu đêm vật vã mình cũng đóng gói được dưới dạng Flatpak, vượt qua được vòng review của FlatHub và được phát hành trên đó, nhân phần mềm vừa cán mốc v0.4. Trong lúc hoàn thiện dần script đóng gói Flatpak thì mình cũng test phần mềm trên các desktop environment khác như KDE, Xfce, LxQt, qua đó phát hiện ra một số bug và sửa.

Ngoài việc soi mã QR từ webcam, CoBang còn quét mã QR từ một ảnh tĩnh. Ảnh tĩnh đó có thể nạp vào bằng phương pháp chọn file, kéo thả từ một ứng dụng khác, và thậm chí là bằng copy paste. Khi chọn file thì có thể chọn file local trên máy hay một file trên Internet (có URL http:// hay sftp://). Đây là một trải nghiệm thú vị khi làm việc với bộ thư viện GTK của Linux. Ví dụ ở hình dưới là mình đang nạp một hình trên Internet qua giao thức SFTP (FTP bọc trong SSH).

sftp-mounted

File đó cũng đang nằm trên server của website này luôn: https://quan.hoabinh.vn/Downloads/QR-code-yte.png

Để nạp file từ SFTP thì mình có thể dùng Nautilus để mount thư mục đó, sau đó dùng kéo-thả để kéo file từ Nautilus qua, thả vào CoBang. Nếu không dùng cách mount thì có thể có thể dán luôn URL của file vào hộp thoại chọn file:

sftp-url

Lợi ích của việc chọn viết app theo hướng native, là sự đồng bộ, hòa hợp với các thành phần khác của Linux, tức là ứng dụng CoBang này khi xử lý URL sftp://, nó có thể tận dụng cấu hình SSH của bạn đối với host đang truy cập. Ví dụ nó hiểu được alias "quanweb" chính là server này, user này, và vì bạn đã setup SSH key cho server này, nó sẽ download được file hình mà không bắt bạn nhập password, tận dụng luôn SSH key để xác thực. Làm được tất cả các điều trên (hiểu alias, đăng nhập, xác thực, tải file về), mình chẳng phải dùng logic lắt léo gì ngoài việc cung cấp cho thư viện Gio một cái URL và gọi hàm read().

def process_passed_image_file(self, chosen_file: Gio.File):
    self.raw_result_buffer.set_text('')
    stream: Gio.FileInputStream = chosen_file.read(None)
    w, h = self.get_preview_size()
    scaled_pix = GdkPixbuf.Pixbuf.new_from_stream_at_scale(stream, w, h, True, None)
    self.insert_image_to_placeholder(scaled_pix)
    stream.seek(0, GLib.SeekType.SET)
    full_buf, etag_out = chosen_file.load_bytes()  # type: GLib.Bytes, Optional[str]
    self.process_passed_rgb_image(full_buf.get_data())

Hiện nay phiên bản của CoBang vẫn còn ở chuỗi 0.x, tức là vẫn còn đơn sơ. Chức năng cốt lõi đã có, đã chạy ổn định. Ý tưởng của mình cho nó vẫn còn nhiều, sẽ còn tốn nhiều công sức để bồi đắp thêm. Trong đó có một tiềm năng mà cộng đồng người dùng Linux trên Reddit đã đề xuất: Làm cho nó hỗ trợ một số dòng điện thoại Linux và tiến tới trở thành app mặc định trên đó. Mặc dù lấn sân sang điện thoại nhưng nó vẫn là native, vì các dòng Linux phone kia cũng sử dụng GTK cho giao diện đồ họa, cũng dùng các thành phần của Linux desktop (không như Android, chỉ ké nhân Linux nhưng phần thịt, vỏ khác hết).

Cập nhật

v0.5.1

Tính năng đáng kể là hiển thị một số loại dữ liệu đặc biệt thu được từ mã QR, ví dụ thông tin Wifi:

WiFi

Và có thể giao tiếp với NetworkManager để lưu thông tin này vào:

Save Wifi