SerinBoT-Swift

요약

개발범위 전체
레포지터리 주소 https://git.meu.works/cenox_kang/SerinBoT-Remake
https://git.meu.works/cenox_kang/serin-swift
레포지터리 생성 일자 2018. 03. 12..
사용한 언어 Swift
사용한 개발 툴 (IDE) Xcode, Terminal, Visual Studio Code
활성화 된 기능 N/A
사용된 라이브러리
  • Sword - Total SDK platform service.
  • Kanna - XML/HTML parser for cross-platform(macOS, iOS, tvOS, watchOS and Linux!).
  • CwlUtils - A collection of Swift utilities as documented on cocoawithlove.com
  • Then - ✨ Super sweet syntactic sugar for Swift initializers
  • SwiftyJSON - The better way to deal with JSON data in Swift.
  • XCGLogger - A debug log framework for use in Swift projects.
  • 개요

    SerinBoT-Swift는 Discord에서 봇으로 사용하기 위해, Sword 라이브러리와 Swift 언어를 기반으로 짜여진 Terminal 기반 애플리케이션입니다.

    Gitlab 내의 SerinBoT-Swift에서 serin-swift로 프로젝트가 이전 및 재작성 되었으며, 이전 SerinBoT-Swift는 아카이브 되었습니다.

    채팅이 주로 이루어지는 Discord 환경에서 사용자가 필요로 하는 기능과 더불어 장난이나 재미를 위한 기능들도 추가되어 있습니다.

    macOS 에서 돌아가는 것을 기본전제로 하여, CwlUtils 라이브러리를 이용하여 시스템의 상태나 사양등을 확인할 수 있는 요소와, macOS 와 Swift 환경에 제공되는 Foundation 라이브러리를 활용하여 제공할 수 있는 서비스 및 한줄로 실행할 수 있는 shell 명령어 들은 직접 채팅을 통하여 실행하고, 그 결과를 볼 수 있습니다.

    구조

    재작성된 Serin의 모든 명령어는, 기존 프로젝트와는 다르게 새롭게 설계한 protocol인 CommandProtocol을 준수하여 재작성 되었습니다. CommandProtocol은 다음과 같은 구조를 가지고 있으며, 해당 구조를 따라 구현한 명령어는 실행 시 등록할 명령어의 Array에 추가함으로써 쉽게 추가할 수 있습니다.

    명령을 구현할 때 설명을 바로 구현체에 넣을 수 있기 때문에, help와 같이 도움말을 보여주는 명령어를 작성하기 위해 일일히 명령어를 긁어 String으로 적을 필요 없이, 등록 시 CommandProtocol 내에 정의된 description을 파싱하여 바로 표시할 수 있습니다. 따라서, 새로운 명령어가 추가되었다고 하여도 일일히 help 명령어를 위한 설명을 작성하지 않아도 됩니다.

    CommandProtocol의 구조

    protocol CommandProtocol {
        var description: String { get }
        var command: String { get }
        var category: CommandCategory { get }
        func function() -> (Message, [String]) -> ()
    }
    

    예시로 구현된 CommandProtocol을 준수하는 샘플

    class SampleCommand: CommandProtocol {
        
        var command: String = "sample"
        var category: CommandCategory = .general
        var description: String = """
        구현체를 설명하기 위한 샘플 명령어에요!
        """
        
        func function() -> (Message, [String]) -> () { { message, args in
          message.reply(with: "이 메소드를 통해 답장을 보낼 수 있어요!")
        } }
        
    }
    

    내장된 Kitura 웹 프레임워크와 Discord 봇과 관련된 기능들은 클래스로써 따로 분리되어 있고, 서로 다른 Queue에서 작동합니다.

    명령어

    명령어는 4개의 카테고리로 나뉘어져 있습니다. 각각 commom admin dev gcp 로 명명되어 있으며, commom을 제외한 명령어는 해당 카테고리를 prefix뒤에 붙이는 것으로 실행이 가능합니다.

    e.g. s!gcp.list s!uwu ㅁㄴㅇㄹ

    각 기능은 다음과 같습니다.

    common - 일반적인 기능들입니다. 도움말 출력, 말 끝에 uwu를 붙여 따라올리기, 채팅 삭제 등의 기능이 들어가있습니다. 별도의 prefix가 필요하지 않습니다.

    admin - 해당 카테고리에 해당하는 명령어는 봇의 어드민만이 사용이 가능하도록 구현된 기능들입니다. Shell 명령어를 실행하거나, 연동되어 있는 애플리케이션에 알림을 전송하는 등의 기능이 구현되어 있습니다.

    dev - 개발과 관련된 명령어들이 이에 해당됩니다. 현재 실행중인 프로세스 버전 출력, 호스트 서버 정보 표시, 업타임 등이 기본으로 구현되어 있고, 앞으로 추가될 명령어들은 우선적으로 이 분류에 넣어 개발을 진행하고 있습니다.

    gcp - Google Cloud 에 생성되어 있는 특정 프로젝트를 봇을 통해 직접 제어할 수 있습니다. 현재 개발중인 부분으로써, VPN 서버를 Google Cloud 내의 Compute Engine을 통해 구성하였는데, 과금이 되는 서비스인 만큼 실행과 종료를 편하게 할 수 있으면 좋겠다고 생각하여 봇에 이 기능을 추가하게 되었습니다.

    help 명령어를 통해 실행 결과를 얻은 모습
    스크린샷 2019-12-30 오후 10.44.28

    특별한 기능

    명령어 실행

    s!admin.exec [명령어] 로 실행중인 호스트에서 간단한 터미널 명령을 실행하고 그 결과를 볼 수 있습니다.

    해당 명렁어는 bash를 통해 실행되며 특별한 권한이 부여된 것은 없습니다.

    코드 상으로는, Swift의 Foundation 안에 있는 Process 클래스를 이용해 명령어를 실행하고, 그 명령어의 STDOUT 과 STDERR 를 실행중인 프로세스에 연결해 업데이트가 있을 시 메세지를 받은 채널로 출력들을 전송합니다.

    출력이 완전히 끝날 때 까지 기다리다 전송하는 방식은 2000자가 넘을 경우 메세지가 잘려버립니다. 출력이 예측 불가능한 터미널 명령어의 특성 상 출력 가능한 데이터가 있을 때 즉시 전송할 수 있도록 하는 것이 이득이라고 생각하였고, 이는 Observer를 만들어 NotificationCenteraddObserver 메소드로 옵저버를 추가한 후, NotificationCenter 가 NSFileHandleDataAvailable 알림을 받아 출력 가능한 데이터가 있으면 문자열로 변환하여 채팅창에 출력하는 방법으로 해결하였습니다.

    또한 프로세스가 종료되었을 때에는 didTerminateNotification을 알림을 통해 프로세스가 종료되었음을 사용자에게 표시합니다.

    웹 프레임워크 연동

    SerinBoT 프로젝트는, Swift를 기반으로 짜여진 웹 프레임워크인 Kitura가 내장되어 있습니다.

    serin.moe 로 접속하면, cenox.co 사이트와 디자인을 통일시킨 기본 프레임워크 페이지가 로딩되며, Discord 채팅창에서 기능을 활성화하면, 여러 엔드포인트가 활성화 되어 연동된 애플리케이션과 상호작용이 가능합니다. 기본 프레임워크 페이지가 예쁩니다. 저만 그렇게 생각하면 말구요.