comparison mservtk.tcl @ 5:b6c495b5eeda

- Use wish8.2 - Ack, use the temp variable we copied the rtlist into! (not the recently blanked out rtlist state variable) - Add some locking to try and fix out of sync problems.. Still broken.
author darius
date Tue, 03 Oct 2000 10:18:34 +0000
parents 32f624fc18cc
children b370e0bbe050
comparison
equal deleted inserted replaced
4:32f624fc18cc 5:b6c495b5eeda
1 #!/usr/bin/env wish8.0 1 #!/usr/bin/env wish8.2
2 2
3 # 3 #
4 # This software is copyright Daniel O'Connor (darius@dons.net.au) 2000 4 # This software is copyright Daniel O'Connor (darius@dons.net.au) 2000
5 # 5 #
6 # Redistribution and use in source and binary forms, with or without 6 # Redistribution and use in source and binary forms, with or without
80 if {$state(rtlist) != ""} { 80 if {$state(rtlist) != ""} {
81 # Copy it so we don't stomp any new additions 81 # Copy it so we don't stomp any new additions
82 set tmp $state(rtlist); 82 set tmp $state(rtlist);
83 set state(rtlist) ""; 83 set state(rtlist) "";
84 84
85 foreach t $state(rtlist) { 85 foreach t $tmp {
86 # log "%s" "Handle $t";
86 n_rthandler [lindex $t 0] [lindex $t 1]; 87 n_rthandler [lindex $t 0] [lindex $t 1];
87 } 88 }
88 } 89 }
89 90
90 if {$state(exit) == 1} { 91 if {$state(exit) == 1} {
255 256
256 # Add the File menu 257 # Add the File menu
257 menubutton .menubar.file -text "File" -menu .menubar.file.m -underline 0; 258 menubutton .menubar.file -text "File" -menu .menubar.file.m -underline 0;
258 menu .menubar.file.m -tearoff 0; 259 menu .menubar.file.m -tearoff 0;
259 .menubar.file.m add command -label " Top" -command "gui_top" 260 .menubar.file.m add command -label " Top" -command "gui_top"
261 .menubar.file.m add command -label " Update Queue" -command "gui_updatequeue"
260 .menubar.file.m add separator; 262 .menubar.file.m add separator;
261 .menubar.file.m add command -label " Quit" -command "quit_now" \ 263 .menubar.file.m add command -label " Quit" -command "quit_now" \
262 -underline 2 -accelerator "Alt-q"; 264 -underline 2 -accelerator "Alt-q";
263 pack .menubar.file -side left; 265 pack .menubar.file -side left;
264 266
338 pack .top.tlist.list -side left -fill both -expand 1; 340 pack .top.tlist.list -side left -fill both -expand 1;
339 scrollbar .top.tlist.scr -command ".top.tlist.list yview"; 341 scrollbar .top.tlist.scr -command ".top.tlist.list yview";
340 pack .top.tlist.scr -side right -fill y; 342 pack .top.tlist.scr -side right -fill y;
341 bind .top.tlist.list <Double-Button-1> { 343 bind .top.tlist.list <Double-Button-1> {
342 queue_song [.top.tlist.list curselection]; 344 queue_song [.top.tlist.list curselection];
345 gui_updatequeue;
343 } 346 }
344 347
345 # Trackinfo 348 # Trackinfo
346 frame .top.tinfo -relief raised -bd 1; 349 frame .top.tinfo -relief raised -bd 1;
347 pack .top.tinfo -side right -fill both -expand 0; 350 pack .top.tinfo -side right -fill both -expand 0;
422 425
423 if {$rtn(code) != 247} { 426 if {$rtn(code) != 247} {
424 if {$rtn(code) == 510} { 427 if {$rtn(code) == 510} {
425 msg_box "Queue" "You can't have the same\nsong in the queue twice!"; 428 msg_box "Queue" "You can't have the same\nsong in the queue twice!";
426 } else { 429 } else {
427 log "Failed to queue track ($rtn(code) $rtn(data))"; 430 log "%s" "Failed to queue track ($rtn(code) $rtn(data))";
428 } 431 }
429 } 432 }
430 } 433 }
431 434
432 proc msg_box {title msg} { 435 proc msg_box {title msg} {
484 } 487 }
485 488
486 proc set_vol {vol} { 489 proc set_vol {vol} {
487 global state; 490 global state;
488 491
492 set cookie [acquire_lock];
489 n_write "VOLUME $vol" 493 n_write "VOLUME $vol"
490 n_getrtn rtn; 494 n_getrtn rtn;
491 495 release_lock $cookie;
496
492 if {$rtn(code) != 255} { 497 if {$rtn(code) != 255} {
493 log "%s" "Couldn't set volume ($rtn(code) $rtn(data))"; 498 log "%s" "Couldn't set volume ($rtn(code) $rtn(data))";
494 } 499 }
495 } 500 }
496 501
497 proc rate_song {rate} { 502 proc rate_song {rate} {
498 global state; 503 global state;
499 504
505 set cookie [acquire_lock];
500 n_write "RATE $rate"; 506 n_write "RATE $rate";
501 n_getrtn rtn; 507 n_getrtn rtn;
508 release_lock $cookie;
502 509
503 if {$rtn(code) != 270} { 510 if {$rtn(code) != 270} {
504 log "%s" "Failed to get rate song ($rtn(code) $rtn(data))"; 511 log "%s" "Failed to get rate song ($rtn(code) $rtn(data))";
505 } 512 }
506 513
507 } 514 }
508 515
509 proc control_player {cmd} { 516 proc control_player {cmd} {
510 global state; 517 global state;
511 518
519 set cookie [acquire_lock];
520 log "%s" "Writing $cmd";
512 n_write "$cmd"; 521 n_write "$cmd";
513 n_getrtn rtn; 522 n_getrtn rtn;
523 release_lock $cookie;
514 524
515 log "%s" "Control Got $rtn(code) $rtn(data)"; 525 log "%s" "Control Got $rtn(code) $rtn(data)";
516 } 526 }
517 527
518 proc gui_top {} { 528 proc gui_top {} {
519 global state; 529 global state;
520 530
531 set cookie [acquire_lock];
521 n_write "TOP" 532 n_write "TOP"
522 n_getrtn rtn; 533 n_getrtn rtn;
534 release_lock $cookie;
523 535
524 set msg "List of songs most likely to be played next\n\n"; 536 set msg "List of songs most likely to be played next\n\n";
525 537
526 foreach t $rtn(lines) { 538 foreach t $rtn(lines) {
527 set tmp [split $t \011]; 539 set tmp [split $t \011];
575 } 587 }
576 588
577 proc gui_updatequeue {} { 589 proc gui_updatequeue {} {
578 global state songs queue; 590 global state songs queue;
579 591
580 if {[info exists state(queuelock)]} {
581 return;
582 }
583
584 set state(queuelock) "";
585
586 log "%s" "Updating queue"; 592 log "%s" "Updating queue";
587 593
588 .bot.queue.list delete 0 end; 594 .bot.queue.list delete 0 end;
589 595
590 con_getqueue queue; 596 con_getqueue queue;
591 597
592 foreach tag [lsort [array names queue]] { 598 foreach tag [lsort [array names queue]] {
593 .bot.queue.list insert end "'$songs($queue($tag):name)' by '$songs($queue($tag):author)' on '$songs($queue($tag):albumname)'"; 599 .bot.queue.list insert end "'$songs($queue($tag):name)' by '$songs($queue($tag):author)' on '$songs($queue($tag):albumname)'";
594 } 600 }
595
596 unset state(queuelock);
597 } 601 }
598 602
599 proc gui_delqueue {id} { 603 proc gui_delqueue {id} {
600 global queue; 604 global queue;
601 605
602 if {$id == ""} { 606 if {$id == ""} {
603 return; 607 return;
604 } 608 }
605 609
610 set cookie [acquire_lock];
606 n_write "UNQUEUE [split $queue($id) {:}]"; 611 n_write "UNQUEUE [split $queue($id) {:}]";
607 n_getrtn rtn; 612 n_getrtn rtn;
608 613 release_lock $cookie;
614
609 if {$rtn(code) != 254} { 615 if {$rtn(code) != 254} {
610 log "%s" "Failed to remove $id ($queue($id))"; 616 log "%s" "Failed to remove $id ($queue($id))";
611 msg_box "Queue" "Failed to dequeue the song"; 617 msg_box "Queue" "Failed to dequeue the song";
612 } 618 }
613 } 619 }
614 620
615 proc gui_updateinfo {} { 621 proc gui_updateinfo {} {
616 global state; 622 global state;
617 623
624 set cookie [acquire_lock];
618 n_write "VOLUME"; 625 n_write "VOLUME";
619 n_getrtn rtn; 626 n_getrtn rtn;
627 release_lock $cookie;
620 628
621 if {$rtn(code) != 235} { 629 if {$rtn(code) != 235} {
622 set vol "??"; 630 set vol "??";
623 } else { 631 } else {
624 set vol "[lindex [lindex $rtn(lines) 0] 0]"; 632 set vol "[lindex [lindex $rtn(lines) 0] 0]";
625 } 633 }
626 634
635 set cookie [acquire_lock];
627 n_write "INFO"; 636 n_write "INFO";
628 n_getrtn rtn; 637 n_getrtn rtn;
638 release_lock $cookie;
629 639
630 if {$rtn(code) == 246} { 640 if {$rtn(code) == 246} {
631 set data [split [lindex $rtn(lines) 0] "\t"]; 641 set data [split [lindex $rtn(lines) 0] "\t"];
632 set author [lindex $data 4]; 642 set author [lindex $data 4];
633 set title [lindex $data 5]; 643 set title [lindex $data 5];
647 if {$rtn(code) != 401} { 657 if {$rtn(code) != 401} {
648 log "%s" "Failed to get track info ($rtn(code) $rtn(data))"; 658 log "%s" "Failed to get track info ($rtn(code) $rtn(data))";
649 } 659 }
650 } 660 }
651 661
662 set cookie [acquire_lock];
652 n_write "STATUS"; 663 n_write "STATUS";
653 n_getrtn rtn; 664 n_getrtn rtn;
665 release_lock $cookie;
654 666
655 if {$rtn(code) != 222} { 667 if {$rtn(code) != 222} {
656 set left "x:xx"; 668 set left "x:xx";
657 set played "x:xx"; 669 set played "x:xx";
658 } else { 670 } else {
675 .top.tinfo.sub.album configure -text "Album: $album"; 687 .top.tinfo.sub.album configure -text "Album: $album";
676 .top.tinfo.sub.misc configure -text "Misc: $misc"; 688 .top.tinfo.sub.misc configure -text "Misc: $misc";
677 .top.tinfo.sub.rate1 configure -text "Rating: $rate1"; 689 .top.tinfo.sub.rate1 configure -text "Rating: $rate1";
678 .top.tinfo.sub.rate2 configure -text "Temporally Adjusted: $rate2"; 690 .top.tinfo.sub.rate2 configure -text "Temporally Adjusted: $rate2";
679 .top.tinfo.sub.vol configure -text "Volume: $vol"; 691 .top.tinfo.sub.vol configure -text "Volume: $vol";
692
680 } 693 }
681 694
682 proc con_getqueue {queuevar} { 695 proc con_getqueue {queuevar} {
683 upvar $queuevar queue; 696 upvar $queuevar queue;
684 697
685 global state; 698 global state;
686 699
687 catch {unset queue}; 700 catch {unset queue};
688 701
702 set cookie [acquire_lock];
689 n_write "QUEUE" 703 n_write "QUEUE"
690 n_getrtn rtn; 704 n_getrtn rtn;
691 705 release_lock $cookie;
706
692 if {$rtn(code) == 225} { 707 if {$rtn(code) == 225} {
693 set i 0; 708 set i 0;
694 foreach line $rtn(lines) { 709 foreach line $rtn(lines) {
695 set foo [split $line \011]; 710 set foo [split $line \011];
696 set id "[lindex $foo 1]:[lindex $foo 2]"; 711 set id "[lindex $foo 1]:[lindex $foo 2]";
712 global state; 727 global state;
713 728
714 catch { unset songs }; 729 catch { unset songs };
715 730
716 foreach i [array names albums "*:"] { 731 foreach i [array names albums "*:"] {
732 set cookie [acquire_lock];
717 n_write "TRACKS $albums($i)"; 733 n_write "TRACKS $albums($i)";
718 n_getrtn rtn; 734 n_getrtn rtn;
735 release_lock $cookie;
736
719 if {$rtn(code) != "228"} { 737 if {$rtn(code) != "228"} {
720 error "Got bogus response to track request ($rtn(code) $rtn(data))"; 738 error "Got bogus response to track request ($rtn(code) $rtn(data))";
721 } 739 }
722 740
723 foreach trk $rtn(lines) { 741 foreach trk $rtn(lines) {
744 762
745 global state; 763 global state;
746 764
747 catch {unset albums}; 765 catch {unset albums};
748 766
767 set cookie [acquire_lock];
749 n_write "ALBUMS"; 768 n_write "ALBUMS";
750 n_getrtn rtn; 769 n_getrtn rtn;
770 release_lock $cookie;
771
751 if {$rtn(code) != 227} { 772 if {$rtn(code) != 227} {
752 error "Server gave bogus response to album request ($rtn(code) $rtn(data))"; 773 error "Server gave bogus response to album request ($rtn(code) $rtn(data))";
753 } 774 }
754 775
755 foreach alb $rtn(lines) { 776 foreach alb $rtn(lines) {
756 set foo [split $alb \011]; 777 set foo [split $alb \011];
757 set id [lindex $foo 0]; 778 set id [lindex $foo 0];
758 set albums($id:) [lindex $foo 0]; 779 if {$id == ""} {
780 continue;
781 }
782 set albums($id:) $id;
759 set albums($id:author) [lindex $foo 1]; 783 set albums($id:author) [lindex $foo 1];
760 set albums($id:name) [lindex $foo 2]; 784 set albums($id:name) [lindex $foo 2];
761 785
762 # log "%s" "Album $i, ID $albums($i:id) called $albums($i:name) by $albums($i:author)"; 786 # log "%s" "Album $id, ID '$albums($id:)' called '$albums($id:name)' by '$albums($id:author)'";
763 } 787 }
764 } 788 }
765 789
766 proc update_timer {} { 790 proc update_timer {} {
767 791
804 } 828 }
805 829
806 if {$rtn(code) != "202"} { 830 if {$rtn(code) != "202"} {
807 error "Unknown response to PASS command - $rtn(code) $rtn(data)" 831 error "Unknown response to PASS command - $rtn(code) $rtn(data)"
808 } 832 }
809 833
834 set state(lock) "";
835 # trace variable state(lock) rw foobar;
836
810 log "%s" "Logged in"; 837 log "%s" "Logged in";
811 } 838 }
812 839
813 proc n_write {text} { 840 proc n_write {text} {
814 global state; 841 global state;
815 842
816 puts $state(serv_fd) $text; 843 puts $state(serv_fd) $text;
844 flush $state(serv_fd);
845
846 if {[eof $state(serv_fd)]} {
847 log "%s" "Server went away on write";
848 exit 1;
849 }
817 # log "%s" "Wrote - $text"; 850 # log "%s" "Wrote - $text";
818
819 flush $state(serv_fd);
820 } 851 }
821 852
822 proc n_rthandler {code data} { 853 proc n_rthandler {code data} {
823 global songs; 854 global songs;
824 855
825 # log "%s" "Got RT - $code $data"; 856 log "%s" "Got RT - $code $data";
826 857
827 switch -- $code { 858 switch -- $code {
828 600 { 859 600 {
829 log "%s" "User '$data' connected"; 860 log "%s" "User '$data' connected";
830 } 861 }
831 862
832 601 { 863 601 {
833 log "%s" "User '$data' disconnected"; 864 log "%s" "User '$data' disconnected";
834 } 865 }
835 866
867 240 -
836 618 - 868 618 -
837 619 - 869 619 -
870 620 -
838 622 - 871 622 -
872 623 -
839 627 - 873 627 -
840 623 { 874 628 -
841 after idle gui_updatequeue; 875 629 {
876 log "%s" "Updating queue on idle";
877 gui_updatequeue;
878 }
879
880 default {
881 log "%s" "Got unhandled RT event $code $data";
842 } 882 }
843 } 883 }
844 } 884 }
845 885
846 proc n_rtinput {} { 886 proc n_rtinput {} {
847 global state; 887 global state;
848 888
849 set rth ""; 889 set rth "";
850 890
851 set line [gets $state(serv_fd)]; 891 while {1} {
852 # log "%s" "Read - $line"; 892 set line [gets $state(serv_fd)];
853 893 if {[eof $state(serv_fd)]} {
854 # Check for RT text 894 log "%s" "Server went away on read";
855 set foo [split $line "\t"]; 895 exit 1;
856 if {[string index $line 0] == "="} { 896 }
857 set rth [list [string range [lindex $foo 0] 1 3] [lrange $foo 1 end]]; 897 # log "%s" "Read - $line";
858 } else { 898 if {$line == ""} {
859 lappend state(tmpphrase) $line 899 return;
860 if {$line == "."} { 900 }
861 set state(pushbuf) [linsert $state(pushbuf) 0 $state(tmpphrase)]; 901 # Check for RT text
862 set state(tmpphrase) ""; 902 set foo [split $line "\t"];
863 } 903 if {[string index $line 0] == "="} {
864 } 904 lappend state(rtlist) [list [string range [lindex $foo 0] 1 3] [lrange $foo 1 end]];
865 905 # log "%s" "RT event";
866 if {$rth != ""} { 906 } else {
867 # n_rthandler [lindex $rth 0] [lindex $rth 1]; 907 lappend state(tmpphrase) $line
868 lappend state(rtlist) $rth; 908 if {$line == "."} {
869 } 909 set state(pushbuf) [linsert $state(pushbuf) 0 $state(tmpphrase)];
910 # log "%s" "push buffer - '$state(tmpphrase)'";
911 set state(tmpphrase) "";
912 }
913 }
914 }
870 } 915 }
871 916
872 proc n_getrtn {var} { 917 proc n_getrtn {var} {
873 upvar $var rtn; 918 upvar $var rtn;
874 global state; 919 global state;
877 catch {unset rtn(code)}; 922 catch {unset rtn(code)};
878 catch {unset rtn(data)}; 923 catch {unset rtn(data)};
879 catch {unset rtn(lines)} 924 catch {unset rtn(lines)}
880 925
881 while {[llength $state(pushbuf)] == 0} { 926 while {[llength $state(pushbuf)] == 0} {
927 # log "%s" "Sleeping for data";
882 vwait state(pushbuf); 928 vwait state(pushbuf);
883 } 929 }
884 930
931 # log "%s" "Waking up, got $state(pushbuf)";
932
885 set buf [lindex $state(pushbuf) 0]; 933 set buf [lindex $state(pushbuf) 0];
886 set state(pushbuf) [lrange $state(pushbuf) 1 end]; 934 set state(pushbuf) [lrange $state(pushbuf) 1 end];
887 935
888 while {1} { 936 while {1} {
889 if {[llength $buf] == 0} { 937 if {[llength $buf] == 0} {
906 954
907 lappend rtn(lines) $line; 955 lappend rtn(lines) $line;
908 } 956 }
909 957
910 if {$gotcode == 0} { 958 if {$gotcode == 0} {
911 log "%s" "Failed to parse phrase (got . before server responce)"; 959 log "%s" "Failed to parse phrase (got . before server response)";
912 } 960 }
913 } 961 }
914 962
915 ################################################################## 963 ##################################################################
916 # Log a message to stderr 964 # Log a message to stderr
925 if {[catch {set csm [eval format {$format} $args]} msg]} { 973 if {[catch {set csm [eval format {$format} $args]} msg]} {
926 set csm "bad log message. format='$format' args='$args'"; 974 set csm "bad log message. format='$format' args='$args'";
927 } 975 }
928 976
929 # Emit the message 977 # Emit the message
930 puts stderr "[clock format [clock seconds] -format {%y/%m/%d %H:%M:%S} -gmt yes]:$fname: $csm"; 978 catch {
931 flush stderr; 979 puts stderr "[clock format [clock seconds] -format {%y/%m/%d %H:%M:%S} -gmt yes]:$fname: $csm";
932 } 980 flush stderr;
933 981 }
934 main; 982 }
983
984 proc acquire_lock {} {
985 global state;
986
987 # Extract the calling function's name
988 if {[catch {set fname [lindex [info level -1] 0]}]} {
989 set fname "unknown";
990 }
991
992 # log "%s" "Acquiring lock for $fname";
993
994 set foo 0;
995
996 if {[info exists state(lock)]} {
997 while {$state(lock) != ""} {
998 set foo 1;
999 log "%s" "$fname waiting for lock (held by [lindex $state(lock) 1])";
1000 vwait state(lock);
1001 }
1002
1003 if {$foo == 1} {
1004 log "%s" "Lock released";
1005 }
1006
1007 }
1008
1009 set cookie [clock clicks];
1010 set state(lock) [list $cookie $fname];
1011 # log "%s" "Lock acquired";
1012 return $cookie;
1013 }
1014
1015 proc release_lock {cookie} {
1016 global state;
1017
1018 # Extract the calling function's name
1019 if {[catch {set fname [lindex [info level -1] 0]}]} {
1020 set fname "unknown";
1021 }
1022
1023 if {$cookie == ""} {
1024 log "%s" "$fname trying to unlock without being locked";
1025 exit 1;
1026 }
1027
1028 if {$cookie != [lindex $state(lock) 0]} {
1029 log "%s" "Lock cookie not matched!";
1030 exit 1;
1031 }
1032
1033 if {$fname != [lindex $state(lock) 1]} {
1034 log "%s" "$fname tried to free [lindex $state(lock) 1]'s lock!";
1035 exit 1;
1036 }
1037
1038 set state(lock) "";
1039 # log "%s" "Lock for $fname now free";
1040 }
1041
1042 proc foobar {n1 n2 op} {
1043 global state;
1044
1045 log "%s" "$op, now $state(lock)";
1046 }
1047
1048 if {[catch {main} msg]} {
1049 catch {tk_dialog .dummy "Error!" $msg error 0 "OK"};
1050 }
1051