⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 channelmenu.cpp

📁 mysee网络直播源代码Mysee Lite是Mysee独立研发的网络视频流媒体播放系统。在应有了P2P技术和一系列先进流媒体技术之后
💻 CPP
字号:
/*
 *  Openmysee
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */
#include "stdafx.h"
#include ".\channelmenu.h"
#include "httprequest.h"
#include "xml.h"
#include "MultiLanguageMgr.h"
#include "configfile.h"
#include "..\layer1\external\md5.h"

static	CChannelMenu*	pChannelMenu = NULL;
extern	TCHAR	g_sAppPath[MAX_PATH];

CChannelMenu::CChannelMenu(void) : h_channelmenu(NULL), h_MenuThread(NULL), 
	channeldataOK(0), ParseDataOK(FALSE), useChannel(FALSE), channelthreadStop(FALSE), updatechannel(0),channelrunning(FALSE),
    xmlurl(_T("http://www.Openmysee.com/program.php")),
    pointcookieurl(_T("http://www.Openmysee.com/")),
    pointurl(_T("http://www.Openmysee.com/member/userstat.php"))
{
	pHttpSession = new HttpRequest;
	pHttpSession->Create();
	pTrayIconMenu = new CTrayIconMenu;
}

CChannelMenu::~CChannelMenu(void)
{
	DestroyMenu(h_channelmenu);

	channelthreadStop = TRUE;
	pHttpSession->SetStopRequest();

	if(h_MenuThread != NULL)
	{
		WaitForSingleObject(h_MenuThread,INFINITE);
		CloseHandle(h_MenuThread);
	}
	delete pHttpSession;
	delete pTrayIconMenu;
}

CChannelMenu*	CChannelMenu::CreateInstance(BOOL useChannel)
{
	if(pChannelMenu == NULL)
	{
		pChannelMenu = new CChannelMenu;
		pChannelMenu->useChannel = useChannel;
		if(useChannel)
		{			
			mystring filestr(g_sAppPath);
			filestr.append(_T("\\config.ini"));
			ConfigFile config(filestr);
			mystring tmp = config.Value(_T("localserver"), _T("channellist"));
			if(!(config.fileNotFound || config.stringNotFound))
				pChannelMenu->xmlurl = tmp;

            tmp = config.Value(_T("localserver"), _T("userdata"));
            if(!(config.fileNotFound || config.stringNotFound))
				pChannelMenu->pointcookieurl = tmp;

            tmp = config.Value(_T("localserver"), _T("postpointurl"));
            if(!(config.fileNotFound || config.stringNotFound))
				pChannelMenu->pointurl = tmp;

			unsigned int threadID;
			pChannelMenu->h_MenuThread = (HANDLE) _beginthreadex(NULL, 0, &_GetMenuThreadProc, pChannelMenu, 0, &threadID);
		}
	}
	return pChannelMenu;
}

CChannelMenu*	CChannelMenu::GetInstance()
{
	return pChannelMenu;
}

void	CChannelMenu::ReleaseInstance()
{
	delete pChannelMenu;
}

extern volatile HWND g_hMainWnd;

unsigned int CALLBACK CChannelMenu::_GetMenuThreadProc(void* lpParameter)
{
	CChannelMenu* pClass = (CChannelMenu*) lpParameter;

    //发生随机数
    srand(GetTickCount());

	int	idleinterval = 0;
	int nextworkingtime = 0;
	int getxmlerrcount = 0;
	while(!pClass->channelthreadStop)
	{
		if(idleinterval >= nextworkingtime )	//当定时器被触发时,开始获取XML的行动
		{
			InterlockedExchange(&pClass->channeldataOK, 0);
			if(!pClass->GetChannelXML())
			{
				if(getxmlerrcount < 3)		//根据已经发生的错误次数制定逐步加长的重试间隔
				{
					nextworkingtime += 1;	//隔1s重试一次
					getxmlerrcount++;
				}
				else if(getxmlerrcount < 6)
				{
					nextworkingtime += 10;	//隔10s重试一次
					getxmlerrcount++;
				}
				else						//放弃重试,等待下一次定时唤醒
				{
                    InterlockedExchange(&pClass->channeldataOK, -1);
					nextworkingtime += 1200;
					getxmlerrcount = 0;
				}
			}
			else
			{
				nextworkingtime += 1200;	//隔20min重试一次
				getxmlerrcount = 0;
				InterlockedExchange(&pClass->channeldataOK, 1);
			}
		}
		else if(pClass->updatechannel == 1)
		{
			nextworkingtime = idleinterval;
			InterlockedExchange(&pClass->updatechannel, 0);
		}


        if(idleinterval%300 == 0)
        {
            pClass->PostAddPoint();
        }

		Sleep(1000);
		idleinterval++;
	}
//	PostMessage(g_hMainWnd, WM_COMMAND, WM_APP + 1, 0);
	return 0;
}

void	CChannelMenu::UpdateChannelNow()
{
    InterlockedExchange(&channeldataOK, 0);
	InterlockedExchange(&updatechannel, 1);
}

BOOL    CChannelMenu::PostAddPoint()
{
    if(channelrunning == FALSE)
        return FALSE;

    mystring deststr(pointurl);
    mystring formatstr;

    deststr.append(_T("?u="));    //userstat?

    TCHAR datastr[36];
    DWORD len = 36;
    if(!HttpRequest::GetCookieEx(pointcookieurl.c_str(), "MYSE_UID", datastr, &len))
        return FALSE;

    deststr.append(datastr);    //userstat?<userid>
    formatstr.append(datastr);
    formatstr.append(_T("06My&SEe#211")/*约定的密钥*/);

    int _rand = rand();
    _stprintf(datastr, _T("&r=%d&h="), _rand); 
    deststr.append(datastr);    //userstat?<userid>&<random num>&
    _stprintf(datastr, _T("%d"), _rand);
    formatstr.append(datastr);

    char* srcstr = new char[formatstr.size() + 20];
    wsprintfA(srcstr, "%s", formatstr.c_str());

    MD5 md5((unsigned char*) srcstr, strlen(srcstr));
    
    char* result = md5.hex_digest();
    delete[] srcstr;

    wsprintf(datastr, "%hs", result);
    delete[] result;

    deststr.append(datastr);    //userstat?<userid>&<random num>&<md5>
	return pHttpSession->OpenRequest(deststr.c_str());
}

BOOL	CChannelMenu::GetChannelXML()
{
    LANGID langid = pTrayIconMenu->GetCurLanguage();

    mystring appendxmlurl(xmlurl);
    if(appendxmlurl.find(_T(".php")) != mystring::npos)     //对于非PHP的URL,应该不应用参数
    {
        switch(langid)
        {
        case MAINLAND_LANG_ID:  //简体中文
            appendxmlurl.append(_T("?lang=zh"));
            break;
        case TAIWAN_LANG_ID:
        case HONGKONG_LANG_ID:  //繁体中文
            appendxmlurl.append(_T("?lang=big5"));
            break;
        case DEFAULT_LANG_ID:   //英文
        default:
            appendxmlurl.append(_T("?lang=en"));
        }
    }
	if(!pHttpSession->OpenRequest(appendxmlurl.c_str()))
		return FALSE;

 //   MessageBox(NULL, "get xml!", "", MB_OK);

	BYTE* tempstr = new BYTE[pHttpSession->getBufLen() + 30];
	memset(tempstr, 0, pHttpSession->getBufLen() + 30);
	pHttpSession->TransBuf(tempstr);
	m_critsec_XMLFile.Lock();
	strXMLFile = (LPCSTR) tempstr;
	m_critsec_XMLFile.Unlock();
	delete[] tempstr;
	return TRUE;
}

#ifdef _UNICODE
static const std::wstring groupname[] = 
{
_T("GROUP"),
_T("SUBGROUP"),
_T("Channel"),
};
#else
static const std::string groupname[] = 
{
_T("GROUP"),
_T("SUBGROUP"),
_T("Channel"),
};
#endif

#define	ChannelPos 2


BOOL	CChannelMenu::ParseChannelXML(HMENU hmenu)
{
	CXML* p_xml = new CXML;
	p_xml->InitXml();
	m_critsec_XMLFile.Lock();
	if(!p_xml->OpenXml(strXMLFile))
	{
		m_critsec_XMLFile.Unlock();
		p_xml->unInitXml();
		delete p_xml;
		return FALSE;
	}
	m_critsec_XMLFile.Unlock();

	if(p_xml->SetNodelist(groupname[0].c_str()) != 0)
		MakePopupItem(p_xml, hmenu, 0);

	if(p_xml->SetNodelist(groupname[ChannelPos].c_str()) != 0)
		MakePopupItem(p_xml, hmenu, ChannelPos);

	p_xml->unInitXml();
	delete p_xml;
	return TRUE;
}

void	CChannelMenu::MakePopupItem(CXML* p_xml, HMENU hmenu, int isubgroup)
{
	BOOL ischannel = (groupname[isubgroup] == _T("Channel"));

	while(p_xml->ToNextNode())
	{
		if(!ischannel)
		{
			HMENU h_appendmenu = CreatePopupMenu();
            if(p_xml->ToSubNodeList(groupname[isubgroup + 1].c_str()) != 0) 	//将组名设定成下一级的组名
            {
			    MakePopupItem(p_xml, h_appendmenu, isubgroup + 1);
                p_xml->BackParentNodeList();
            }

            if((isubgroup + 1 != ChannelPos) && (p_xml->ToSubNodeList(groupname[ChannelPos].c_str()) != 0))   //在本组下面寻找Channel并加入
            {
                MakePopupItem(p_xml, h_appendmenu, ChannelPos);
                p_xml->BackParentNodeList();
            }

            if(GetMenuItemCount(h_appendmenu) <= 0)            //如果最后子菜单中一项都没有, 这个node是错误的, 抛弃它
            {
                assert(0);
                DestroyMenu(h_appendmenu);
            }
            else
            {
                mystring str;
			    p_xml->GetCurNodeAttrValue(str, _T("Name"));
			    AppendMenu(hmenu, MF_STRING | MF_POPUP, (UINT_PTR) h_appendmenu, str.c_str());
            }
		}
		else//本身已经是Channel,加入菜单中
		{
			ChannelData data;
			p_xml->GetCurNodeAttrValue(data.name, _T("Name"));
			p_xml->GetCurNodeAttrValue(data.url, _T("URL"));
			channellist.push_back(data);
			AppendMenu(hmenu, MF_STRING , TRAYWM_CHANNELSTART + channellist.size() - 1, data.name.c_str());
		}
	}

}


LPCTSTR	CChannelMenu::GetChannelByCmdID(DWORD	m_cmdID)
{
	if(m_cmdID < TRAYWM_CHANNELSTART || m_cmdID > TRAYWM_CHANNELEND)
		return NULL;
	size_t index = m_cmdID - TRAYWM_CHANNELSTART;
	if(index >= channellist.size())
		return NULL;	

	channellist[index].desc.append(channellist[index].url.c_str());

	return channellist[index].url.c_str();
}

namespace{
//一份默认的菜单
UINT_PTR	m_traycmd[] = 
{
TRAYWM_HOMEPAGE,
CTrayIconMenu::ID_SEPERATOR,
//CTrayIconMenu::ID_EXTERNAL, 0,
//CTrayIconMenu::ID_SEPERATOR,
CTrayIconMenu::ID_POPUP,
       TRAYWM_UPDATE,
       CTrayIconMenu::ID_LANGUAGE,
CTrayIconMenu::ID_END,
CTrayIconMenu::ID_SEPERATOR,
CTrayIconMenu::ID_POPUP,
       TRAYWM_HELP,
       TRAYWM_NETWORK,
       TRAYWM_EMAIL,
       TRAYWM_ABOUT,
CTrayIconMenu::ID_END,
CTrayIconMenu::ID_SEPERATOR,
TRAYWM_EXIT,
CTrayIconMenu::ID_END};

//不同语言的菜单文本,必须和数据严格对应,每一个数据项在文本里都应该有一个*,包括ID_END, ID_SEPERATOR等
//ID_EXTERNAL除外,其后接一项没有*,而ID_POPUP后应该增加一项*作为标记
/*const TCHAR	m_traystrgb[] = 
	_T("首页(&P)*-*频道(&C)*-*设置(&S)*SUBSTART*检查更新(&U)*选择语言(&L)*END*-*帮助(&H)*SUBSTART*使用帮助(&H)*判定网络(&N)*电子邮件(&E)*关于(&A)*END*-*退出(&E)*END*");
*/	
const TCHAR	m_traystrgb[] = 
	_T("首页(&P)*-*设置(&S)*SUBSTART*检查更新(&U)*选择语言(&L)*END*-*帮助(&H)*SUBSTART*使用帮助(&H)*判定网络(&N)*电子邮件(&E)*关于(&A)*END*-*退出(&E)*END*");
	
	
//这里用"-"表示一个分隔符,"SUBSTART"表示开始一个新子菜单,"END"表示一个菜单结束。也可以换成任何方便的字符,程序并不理会它们
const UINT  m_channellisthandlepos = 3;
}

BOOL	CChannelMenu::ShowRButtonTIMenu(HWND hparent)
{
	h_channelmenu = CreatePopupMenu();	//初始化一个提示的菜单
	AppendMenu(h_channelmenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);   //加条分隔线意思一下,以防万一……

    m_traycmd[m_channellisthandlepos] = (UINT_PTR) h_channelmenu;;

	pTrayIconMenu->ShowMenu(hparent, m_traycmd, m_traystrgb);

	DestroyMenu(h_channelmenu);			//放弃生成的菜单
	h_channelmenu = NULL;
	ParseDataOK = FALSE;				//因为生成的菜单已放弃,所以已正确解析的标记变成FALSE

	return TRUE;
}

void	CChannelMenu::OnPopupMenu(HMENU hmenu, int popuppos)
{
	if(pTrayIconMenu->OnMenuPopup(hmenu, popuppos))
		return;

	if(hmenu != h_channelmenu)	//不是频道窗口不需要处理
		return;

	int count = GetMenuItemCount(hmenu);
	if(count == -1)				//菜单错误,放弃解析
		return;
	for(int i = 0; i < count; i++)
		DeleteMenu(hmenu, 0, MF_BYPOSITION);	//清除掉整个菜单里的内容

    MultiLanguage langDll;
	if(channeldataOK == 0)		//数据未准备好
    {
	    AppendMenu(h_channelmenu, MF_STRING | MF_DISABLED , (UINT_PTR) 0, langDll.GetStringByStr(_T("数据读取中...")));
    }
    else if(channeldataOK == -1)     //获取数据错误
    {
        AppendMenu(h_channelmenu, MF_STRING | MF_DISABLED , (UINT_PTR) 0, langDll.GetStringByStr(_T("数据读取失败!")));
        AppendMenu(hmenu, MF_SEPARATOR, 0, NULL);
		AppendMenu(hmenu, MF_STRING, TRAYWM_UPDATECHANNEL, langDll.GetStringByStr(_T("更新频道列表")));
    }
    else
    {
	    if(ParseChannelXML(hmenu) == TRUE)
	    {
		    AppendMenu(hmenu, MF_SEPARATOR, 0, NULL);
		    AppendMenu(hmenu, MF_STRING, TRAYWM_UPDATECHANNEL, langDll.GetStringByStr(_T("更新频道列表")));
	    }
	    else
	    {
		    AppendMenu(hmenu, MF_STRING | MF_DISABLED, 0, langDll.GetStringByStr(_T("频道文件解析失败")));
	    }
    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -