#!/usr/bin/env ruby # -*- coding: utf-8 -*- require 'digest/md5' require 'fileutils' require 'rack' require 'uri' require 'sekkaconfig' require 'sekka/sekkaversion' DICTDIR = File.expand_path( "~/.sekka-server" ) DICTURL = "https://raw.githubusercontent.com/kiyoka/sekka/master/public_dict/" + SekkaVersion.dictVersion PIDFILE = DICTDIR + "/pid" TC_OPTS = "#xmsiz=256m" TC_FILE = sprintf( "%s/SEKKA-JISYO-%s.N.tch%s", DICTDIR, SekkaVersion.dictVersion, TC_OPTS ) TSV_FILE = sprintf( "%s/SEKKA-JISYO-%s.N.tsv", DICTDIR, SekkaVersion.dictVersion ) TSV_SUMFILE = sprintf( "%s/SEKKA-JISYO-%s.N.md5", DICTDIR, SekkaVersion.dictVersion ) LDB_FILE = sprintf( "%s/SEKKA-JISYO-%s.N.ldb.tar.gz", DICTDIR, SekkaVersion.dictVersion ) LDB_SUMFILE = sprintf( "%s/SEKKA-JISYO-%s.N.ldb.tar.gz.md5", DICTDIR, SekkaVersion.dictVersion ) GDBM_FILE = sprintf( "%s/SEKKA-JISYO-%s.N.db", DICTDIR, SekkaVersion.dictVersion ) LEVELDB_FILE = sprintf( "%s/SEKKA-JISYO-%s.N.ldb", DICTDIR, SekkaVersion.dictVersion ) TSV_URLURL = sprintf( "%s/SEKKA-JISYO-%s.N.url", DICTURL, SekkaVersion.dictVersion ) TSV_SUMURL = sprintf( "%s/SEKKA-JISYO-%s.N.md5", DICTURL, SekkaVersion.dictVersion ) LDB_URLURL = sprintf( "%s/SEKKA-JISYO-%s.N.ldb.tar.gz.url", DICTURL, SekkaVersion.dictVersion ) LDB_SUMURL = sprintf( "%s/SEKKA-JISYO-%s.N.ldb.tar.gz.md5", DICTURL, SekkaVersion.dictVersion ) MEMCACHED = "localhost:11211" # memcahced def getSekkaDbInfo( env ) if env.has_key?( 'SEKKA_DB' ) m = env['SEKKA_DB'].match( /^redis:(.*)$/ ) if m dictSource = if 0 == m[1].size dictSource = "localhost" else dictSource = m[1] end [ :redis, dictSource ] elsif m = ENV['SEKKA_DB'].match( /^tokyo[a-z]+$/ ) [ :tokyocabinet, nil ] elsif m = ENV['SEKKA_DB'].match( /^gdbm$/i ) [ :gdbm, nil ] elsif m = ENV['SEKKA_DB'].match( /^level[a-z]+$/i ) [ :leveldb, nil ] else raise RuntimeError, "Error: env var SEKKA_DB requires [redis:hostname] or [redis:] or [tokyocabinet] or [leveldb]" end else [ :tokyocabinet, nil ] end end def checkJisyoIsInstalled( dictType, dictSource ) key = "SEKKA:VERSION" STDERR.printf( "Info: Checking SEKKA jisyo on #{dictType} server...\n" ) begin result = case dictType when :gdbm require 'sekka/kvs' kvs = Kvs.new( :gdbm ) kvs.open( dictSource ) ret = kvs.get( key ) kvs.close() ret when :leveldb require 'sekka/kvs' kvs = Kvs.new( :leveldb ) kvs.open( dictSource ) ret = kvs.get( key ) kvs.close() ret when :tokyocabinet require 'tokyocabinet' require 'sekka/kvs' kvs = Kvs.new( :tokyocabinet ) kvs.open( dictSource ) ret = kvs.get( key ) kvs.close() ret when :redis begin require 'redis' require 'sekka/kvs' redis = Kvs.new( :redis ) redis.open( dictSource ) ret = redis.get( key ) redis.close() ret rescue => e STDERR.printf( "Error: sekka-server can't connect to redis(port=%s)...\n", dictSource ) exit 1 end end end end def downloadFile( targetfile, sumfile, urlurl, sumurl ) if not File.exist?( targetfile ) STDERR.printf( "Info: Downloading SEKKA-JISYO\n" ) # 辞書をダウンロードする cmd = sprintf( "curl %s", urlurl ) STDERR.printf( "Command : %s\n", cmd ) targeturl = open( "|" + cmd ) { |f| f.read } STDERR.printf( " download URL of target file : %s\n", targeturl ); cmd = sprintf( "curl -o %s %s", targetfile, targeturl ) STDERR.printf( "Command : %s\n", cmd ) system( cmd ) cmd = sprintf( "curl -o %s %s", sumfile, sumurl ) STDERR.printf( "Command : %s\n", cmd ) system( cmd ) # チェックサムを確認する downloadSum = "" open( targetfile ) { |f| dataBody = f.read downloadSum = Digest::MD5.hexdigest( dataBody ) } open( sumfile ) { |f| correctSum = f.readline.chomp.split[0] STDERR.printf( " downloaded file's MD5 : %s\n", downloadSum ) STDERR.printf( " correct MD5 : %s\n", correctSum ) if downloadSum == correctSum STDERR.printf( "Info: downloaded file [%s] verify OK.\n", targetfile ) else STDERR.printf( "Error: downloaded file [%s] verify NG.\n", targetfile ) File.unlink( targetfile ) exit( 1 ) end } end end def main if not File.directory?( DICTDIR ) Dir.mkdir( DICTDIR ) STDERR.printf( "Info: created directory [%s]\n", DICTDIR ) end # sekka-server自身のpidを書きこむ(デーモン化したときの停止用) open( PIDFILE, "w" ) {|f| f.printf( "%d\n", Process.pid ) } # 環境変数からHTTPプロキシサーバーの情報を取得する proxyHost = nil proxyPort = nil if ENV.key?( 'http_proxy' ) uri = URI.parse ENV[ 'http_proxy' ] proxyPort = uri.port proxyHost = uri.host end # 環境変数から、DBの接続先情報を取得する。 ( dictType, dictSource ) = getSekkaDbInfo( ENV ) # 必要なファイルをダウンロードする case dictType when :leveldb downloadFile( LDB_FILE, LDB_SUMFILE, LDB_URLURL, LDB_SUMURL ) else downloadFile( TSV_FILE, TSV_SUMFILE, TSV_URLURL, TSV_SUMURL ) end case dictType when :gdbm # GDBMに辞書が投入済みか確認する ok = checkJisyoIsInstalled( dictType, GDBM_FILE ) unless ok # tsvファイルをuploadする STDERR.printf( "Info: Uploading...\n" ) cmd = sprintf( "sekka-jisyo restore %s %s", TSV_FILE, GDBM_FILE ) STDERR.printf( "Command : %s\n", cmd ) system( cmd ) end STDERR.printf( "Info: [OK]\n" ) dictSource = GDBM_FILE when :leveldb # GDBMに辞書が展開済みか確認する ok = checkJisyoIsInstalled( dictType, LDB_FILE ) unless ok # tar.gzを展開する STDERR.printf( "Info: Extracting...\n" ) cmd = sprintf( "tar zxCf %s %s", DICTDIR, LDB_FILE ) STDERR.printf( "Command : %s\n", cmd ) system( cmd ) end STDERR.printf( "Info: [OK]\n" ) dictSource = LEVELDB_FILE when :tokyocabinet # TokyoCabinetに辞書が投入済みか確認する ok = checkJisyoIsInstalled( dictType, TC_FILE ) unless ok # tsvファイルをuploadする STDERR.printf( "Info: Uploading...\n" ) cmd = sprintf( "sekka-jisyo restore %s %s", TSV_FILE, TC_FILE ) STDERR.printf( "Command : %s\n", cmd ) system( cmd ) end STDERR.printf( "Info: [OK]\n" ) dictSource = TC_FILE when :redis # redisサーバーに辞書が投入済みか確認する ok = checkJisyoIsInstalled( dictType, dictSource ) unless ok # tsvファイルをuploadする。 STDERR.printf( "Info: Uploading...\n" ) cmd = sprintf( "sekka-jisyo restore %s %s:%s", TSV_FILE, dictType, dictSource ) STDERR.printf( "Command : %s\n", cmd ) system( cmd ) end STDERR.printf( "Info: [OK]\n" ) else raise RuntimeError, sprintf( "Error: unknown dictType [%s]", dictType ) end # 設定項目をConfigオブジェクトに代入 SekkaServer::Config.setup( dictType, dictSource, MEMCACHED, 12929, proxyHost, proxyPort ) # rackに渡すための sekka.ru のインストールパスを求める。 vendordir = File.expand_path(File.dirname(__FILE__) + "/../lib") if RbConfig::CONFIG[ 'vendordir' ] if File.exists? RbConfig::CONFIG[ 'vendordir' ] + "/sekka.ru" vendordir = RbConfig::CONFIG[ 'vendordir' ] end end # print "vendordir = " + vendordir + "\n" # サーバー起動 Rack::Server.start( :environment => "development", :pid => nil, :Port => SekkaServer::Config.listenPort, :Host => "0.0.0.0", :AccessLog => [], :config => vendordir + "/sekka.ru" ) end main()