#!/usr/bin/env ruby ######################################################################## #-- # # FILE: tikfetch -- Example of using the Ruby MikroTik API in Ruby # #++ # Author:: Aaron D. Gifford - https://aarongifford.com/ # Copyright:: Copyright (c) 2009-2020, InfoWest, Inc. # License:: BSD license #-- # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, the above list of authors and contributors, this list of # conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. Neither the name of the author(s) or copyright holder(s) nor the # names of any contributors may be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S), AUTHOR(S) AND # CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY # AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL # IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), AUTHOR(S), OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # DCONSEQUENTIAL AMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF # THE POSSIBILITY OF SUCH DAMAGE. ######################################################################## # encoding: ASCII-8BIT $LOAD_PATH.unshift(File.dirname(__FILE__)+'/../lib') require 'rubygems' require 'mtik' def usage(msg='') STDERR.print( (msg.size > 0 ? msg + "\n\n" : '') + "Usage: #{$0} [-s|--ssl] [-u|--unencrypted_plaintext] [-v|--verbose] [ [ [ ... ]]]\n" + " --unencrypted_plaintext OR -u - Use the 6.43+ login API even if NOT\n" + " using SSL.\n" + " --ssl OR -s - Use SSL for the API connection.\n" + " --verbose OR -v - Enable verbose output via STDOUT.\n" ) exit(-1) end use_ssl = unencrypted_plaintext = verbose = false while !ARGV[0].nil? && ARGV[0][0] == '-' arg = ARGV.shift case arg when '--ssl', '-s' usage("Please do not repeat the --ssl (or -s) parameter") if use_ssl use_ssl = true when '--unencrypted_plaintext', '-u' usage("Please do not repeat the --unencrypted_plaintext (or -u) parameter") if unencrypted_plaintext unencrypted_plaintext = true when '--verbose', '-v' usage("Please do not repeat the --verbose (or -v) parameter") if verbose verbose = true else usage("Unknown argument #{arg.inspect}") end end usage("Too few arguments.") if ARGV.size < 4 ## Permit setting use_ssl and unencrypted_plaintext via environment variables: use_ssl = true if ENV['MTIK_SSL'] unencrypted_plaintext = true if ENV['MTIK_UNENCRYPTED_PLAINTEXT'] verbose = true if ENV['MTIK_VERBOSE'] MTik::verbose = verbose args = { :host => ARGV.shift, :user => ARGV.shift, :pass => ARGV.shift, :ssl => use_ssl, :unencrypted_plaintext => unencrypted_plaintext } begin mt = MTik::Connection.new(args) rescue Errno::ETIMEDOUT, Errno::ENETUNREACH, Errno::EHOSTUNREACH, MTik::Error => e print ">>> ERROR CONNECTING: #{e}\n" exit end ## List all files: files = Hash.new mt.get_reply_each('/file/getall') do |req, s| unless s.key?('!done') files[s['name']] = true end end while ARGV.length > 0 url = ARGV.shift if ARGV.length > 0 filename = ARGV.shift else filename = File.basename(url) end if files.key?(filename) print ">>> ERROR: There is a file named '#{filename}' already on the device.\n" else print ">>> OK: Fetching file '#{filename}' from URL '#{url}'...\n" oldbytes = 0 totalbytes = nil oldtime = starttime = Time.now mt.fetch(url, filename, 120) do |status, total, bytes, req| now = Time.now case status when 'connecting' starttime = now print ">>> OK: Connecting to '#{url}' to download file '#{filename}'\n" when 'requesting' starttime = now print ">> OK: Connected. Sending request for '#{filename}'...\n" when 'downloading' # Unfortunately, the 'total' parameter is only valid for a # 'downloading' status update, so we save the value. totalbytes = total if totalbytes.nil? print ( ">>> OK: Downloaded #{bytes} KB of #{total} KB " + '(%0.2f KBps, %0.2f avgKBps) of ' + "'#{filename}' " + (total > 0 ? '%0.2f' % (100.0*bytes/total) : '0') + '%%' + (oldbytes == bytes ? ' *STALLED*' : '') + "\n" ) % [(bytes-oldbytes)/(now-oldtime), bytes/(now-starttime)] oldbytes = bytes when 'finished' unless totalbytes.nil? print ( ">>> OK: Downloaded #{totalbytes} KB of #{totalbytes} KB " + '(%0.2f KBps, %0.2f avgKBps) of ' + "'#{filename}' 100.00%%\n" ) % [(totalbytes-oldbytes)/(now-oldtime), totalbytes/(now-starttime)] end print ">>> OK: File '#{filename}' download finished in #{'%0.2f' % [now-starttime]} seconds.\n" when 'failed' print ">>> ERROR: File '#{filename}' download failed!\n" else print ">>> ERROR: The following trap error occured: #{status}\n" end oldtime = now end end end mt.wait_all print "\n" print "SIZE CREATED FILENAME\n" print "====================================================================\n" mt.get_reply_each('/file/getall') do |req, s| unless s.key?('!done') s['size'] = 'directory' if s['type'] == 'directory' print "#{(s['size']+' ')[0,10]} #{s['creation-time']} #{s['name']}\n" end end print "\n" mt.close