import_bart.sh 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. #!/bin/bash
  2. # BART Import Script for Open OSCAR Server
  3. # This script imports BART (Buddy ART) asset files into Open OSCAR Server
  4. # via the management API.
  5. #
  6. # Compatible with macOS and Linux terminals
  7. set -e
  8. # Ensure we're using bash and have proper error handling
  9. if [ -z "$BASH_VERSION" ]; then
  10. echo "Error: This script requires bash" >&2
  11. exit 1
  12. fi
  13. # Default values
  14. API_BASE_URL="http://localhost:8080"
  15. VERBOSE=false
  16. DRY_RUN=false
  17. BART_TYPE=""
  18. TARGET_FILES=()
  19. # Colors for output
  20. RED='\033[0;31m'
  21. GREEN='\033[0;32m'
  22. YELLOW='\033[1;33m'
  23. BLUE='\033[0;34m'
  24. NC='\033[0m' # No Color
  25. usage() {
  26. echo "Usage: $0 [OPTIONS] -t <type> <file_path> [file_path...]"
  27. echo ""
  28. echo "Import BART assets into Open OSCAR Server"
  29. echo ""
  30. echo "Arguments:"
  31. echo " file_path Path to BART asset file(s) to import"
  32. echo " Files should be named by their hash (hexadecimal)"
  33. echo " Multiple files can be specified for bulk import"
  34. echo ""
  35. echo "Options:"
  36. echo " -t, --type TYPE BART type to import (required)"
  37. echo " Valid types: buddy_icon_small, buddy_icon, status_str, arrive_sound,"
  38. echo " rich_text, superbuddy_icon, radio_station, buddy_icon_big,"
  39. echo " status_str_tod, current_av_track, depart_sound, im_chrome,"
  40. echo " im_sound, im_chrome_xml, im_chrome_immers, emoticon_set,"
  41. echo " encr_cert_chain, sign_cert_chain, gateway_cert"
  42. echo " -u, --url URL API base URL (default: http://localhost:8080)"
  43. echo " -v, --verbose Enable verbose output"
  44. echo " -d, --dry-run Show what would be uploaded without actually uploading"
  45. echo " -h, --help Show this help message"
  46. echo ""
  47. echo "Examples:"
  48. echo " $0 -t buddy_icon /path/to/bart/abc123def456"
  49. echo " $0 --type status_str --verbose --dry-run /path/to/file1 /path/to/file2"
  50. echo " $0 -t arrive_sound /path/to/files/*"
  51. }
  52. log_info() {
  53. echo -e "${BLUE}[INFO]${NC} $1"
  54. }
  55. log_success() {
  56. echo -e "${GREEN}[SUCCESS]${NC} $1"
  57. }
  58. log_warning() {
  59. echo -e "${YELLOW}[WARNING]${NC} $1"
  60. }
  61. log_error() {
  62. echo -e "${RED}[ERROR]${NC} $1"
  63. }
  64. log_verbose() {
  65. if [ "$VERBOSE" = true ]; then
  66. echo -e "${BLUE}[VERBOSE]${NC} $1"
  67. fi
  68. }
  69. command_exists() {
  70. command -v "$1" >/dev/null 2>&1
  71. }
  72. is_hex_string() {
  73. local string="$1"
  74. # Check if string contains only hexadecimal characters (0-9, a-f, A-F)
  75. if [[ "$string" =~ ^[0-9a-fA-F]+$ ]]; then
  76. return 0
  77. else
  78. return 1
  79. fi
  80. }
  81. # Normalize path for cross-platform compatibility
  82. normalize_path() {
  83. local path="$1"
  84. # Remove trailing slashes and normalize the path
  85. echo "$path" | sed 's|/*$||'
  86. }
  87. get_bart_type_number() {
  88. case "$1" in
  89. "buddy_icon_small") echo "0" ;;
  90. "buddy_icon") echo "1" ;;
  91. "status_str") echo "2" ;;
  92. "arrive_sound") echo "3" ;;
  93. "rich_text") echo "4" ;;
  94. "superbuddy_icon") echo "5" ;;
  95. "radio_station") echo "6" ;;
  96. "buddy_icon_big") echo "12" ;;
  97. "status_str_tod") echo "13" ;;
  98. "current_av_track") echo "15" ;;
  99. "depart_sound") echo "96" ;;
  100. "im_chrome") echo "129" ;;
  101. "im_sound") echo "131" ;;
  102. "im_chrome_xml") echo "136" ;;
  103. "im_chrome_immers") echo "137" ;;
  104. "emoticon_set") echo "1024" ;;
  105. "encr_cert_chain") echo "1026" ;;
  106. "sign_cert_chain") echo "1027" ;;
  107. "gateway_cert") echo "1028" ;;
  108. *) echo "" ;;
  109. esac
  110. }
  111. get_bart_type_name() {
  112. case "$1" in
  113. "0") echo "buddy_icon_small" ;;
  114. "1") echo "buddy_icon" ;;
  115. "2") echo "status_str" ;;
  116. "3") echo "arrive_sound" ;;
  117. "4") echo "rich_text" ;;
  118. "5") echo "superbuddy_icon" ;;
  119. "6") echo "radio_station" ;;
  120. "12") echo "buddy_icon_big" ;;
  121. "13") echo "status_str_tod" ;;
  122. "15") echo "current_av_track" ;;
  123. "96") echo "depart_sound" ;;
  124. "129") echo "im_chrome" ;;
  125. "131") echo "im_sound" ;;
  126. "136") echo "im_chrome_xml" ;;
  127. "137") echo "im_chrome_immers" ;;
  128. "1024") echo "emoticon_set" ;;
  129. "1026") echo "encr_cert_chain" ;;
  130. "1027") echo "sign_cert_chain" ;;
  131. "1028") echo "gateway_cert" ;;
  132. *) echo "unknown_type_$1" ;;
  133. esac
  134. }
  135. check_prerequisites() {
  136. if ! command_exists curl; then
  137. log_error "curl is required but not installed"
  138. exit 1
  139. fi
  140. }
  141. test_api() {
  142. log_info "Testing API connectivity..."
  143. local response
  144. local http_code
  145. if response=$(curl -s -w "%{http_code}" "$API_BASE_URL/bart?type=0" 2>/dev/null); then
  146. # Extract HTTP code from response (last 3 characters)
  147. http_code=$(echo "$response" | tail -c 4)
  148. if [ "$http_code" = "200" ]; then
  149. log_success "API is accessible"
  150. return 0
  151. else
  152. log_error "API returned HTTP $http_code"
  153. return 1
  154. fi
  155. else
  156. log_error "Failed to connect to API at $API_BASE_URL"
  157. return 1
  158. fi
  159. }
  160. upload_bart_asset() {
  161. local file_path="$1"
  162. local bart_type="$2"
  163. local hash="$3"
  164. log_verbose "Uploading $file_path (type: $bart_type, hash: $hash)"
  165. if [ "$DRY_RUN" = true ]; then
  166. log_info "[DRY RUN] Would upload: $file_path -> type=$bart_type, hash=$hash"
  167. return 0
  168. fi
  169. local response
  170. local http_code
  171. # Upload the file
  172. if response=$(curl -s -w "%{http_code}" \
  173. -X POST \
  174. -H "Content-Type: application/octet-stream" \
  175. --data-binary "@$file_path" \
  176. "$API_BASE_URL/bart/$hash?type=$bart_type" 2>/dev/null); then
  177. # Extract HTTP code from response (last 3 characters)
  178. http_code=$(echo "$response" | tail -c 4)
  179. # Extract response body (all except last 3 characters)
  180. # Use a more portable approach that works on both macOS and Linux
  181. response_length=$(echo "$response" | wc -c)
  182. response_body_length=$((response_length - 4))
  183. response_body=$(echo "$response" | head -c "$response_body_length")
  184. case "$http_code" in
  185. 201)
  186. log_success "Uploaded $hash"
  187. if [ "$VERBOSE" = true ]; then
  188. echo "$response_body"
  189. fi
  190. return 0
  191. ;;
  192. 409)
  193. log_warning "Asset $hash already exists"
  194. return 0
  195. ;;
  196. 400)
  197. log_error "Bad request for $hash (type: $bart_type)"
  198. echo "$response_body"
  199. return 1
  200. ;;
  201. 413)
  202. log_error "File too large for $hash (type: $bart_type)"
  203. return 1
  204. ;;
  205. *)
  206. log_error "Upload failed for $hash (type: $bart_type) - HTTP $http_code"
  207. echo "$response_body"
  208. return 1
  209. ;;
  210. esac
  211. else
  212. log_error "Failed to upload $hash (type: $bart_type)"
  213. return 1
  214. fi
  215. }
  216. process_file() {
  217. local file_path="$1"
  218. file_path=$(normalize_path "$file_path")
  219. if [ ! -f "$file_path" ]; then
  220. log_error "File $file_path does not exist"
  221. return 1
  222. fi
  223. log_info "Processing file: $file_path"
  224. local filename=$(basename "$file_path")
  225. # Validate that filename is a hexadecimal string
  226. if ! is_hex_string "$filename"; then
  227. log_error "Cannot process file '$filename' - filename is not a valid hexadecimal string"
  228. return 1
  229. fi
  230. if upload_bart_asset "$file_path" "$BART_TYPE_NUMBER" "$filename"; then
  231. log_success "Successfully processed file: $file_path"
  232. return 0
  233. else
  234. log_error "Failed to process file: $file_path"
  235. return 1
  236. fi
  237. }
  238. while [[ $# -gt 0 ]]; do
  239. case $1 in
  240. -t|--type)
  241. BART_TYPE="$2"
  242. shift 2
  243. ;;
  244. -u|--url)
  245. API_BASE_URL="$2"
  246. shift 2
  247. ;;
  248. -v|--verbose)
  249. VERBOSE=true
  250. shift
  251. ;;
  252. -d|--dry-run)
  253. DRY_RUN=true
  254. shift
  255. ;;
  256. -h|--help)
  257. usage
  258. exit 0
  259. ;;
  260. -*)
  261. log_error "Unknown option $1"
  262. usage
  263. exit 1
  264. ;;
  265. *)
  266. TARGET_FILES+=("$1")
  267. shift
  268. ;;
  269. esac
  270. done
  271. if [ -z "$BART_TYPE" ]; then
  272. log_error "BART type is required"
  273. usage
  274. exit 1
  275. fi
  276. if [ ${#TARGET_FILES[@]} -eq 0 ]; then
  277. log_error "No file path provided"
  278. usage
  279. exit 1
  280. fi
  281. # Validate BART type
  282. BART_TYPE_NUMBER=$(get_bart_type_number "$BART_TYPE")
  283. if [ -z "$BART_TYPE_NUMBER" ]; then
  284. log_error "Invalid BART type: $BART_TYPE"
  285. log_error "Valid types: buddy_icon_small, buddy_icon, status_str, arrive_sound, rich_text, superbuddy_icon, radio_station, buddy_icon_big, status_str_tod, current_av_track, depart_sound, im_chrome, im_sound, im_chrome_xml, im_chrome_immers, emoticon_set, encr_cert_chain, sign_cert_chain, gateway_cert"
  286. exit 1
  287. fi
  288. main() {
  289. log_info "BART Import Script for Open OSCAR Server"
  290. log_info "========================================"
  291. log_info "Target files: ${TARGET_FILES[*]}"
  292. log_info "BART type: $BART_TYPE (type number: $BART_TYPE_NUMBER)"
  293. if [ "$DRY_RUN" = true ]; then
  294. log_warning "DRY RUN MODE - No files will be uploaded"
  295. fi
  296. check_prerequisites
  297. if [ "$DRY_RUN" = false ]; then
  298. test_api
  299. fi
  300. local total_errors=0
  301. # Process each file
  302. # Ensure array is properly expanded for cross-platform compatibility
  303. if [ ${#TARGET_FILES[@]} -gt 0 ]; then
  304. for target_path in "${TARGET_FILES[@]}"; do
  305. if process_file "$target_path"; then
  306. # Success is logged by process_file
  307. :
  308. else
  309. total_errors=$((total_errors + 1))
  310. fi
  311. done
  312. fi
  313. # Summary
  314. log_info "Import completed!"
  315. log_info "Total errors: $total_errors"
  316. if [ $total_errors -eq 0 ]; then
  317. log_success "All operations completed successfully"
  318. exit 0
  319. else
  320. log_error "Some operations failed"
  321. exit 1
  322. fi
  323. }
  324. main